So here is my dart version of java's huffman algorithm. I have a problem with getCodeForChar
function, it says what return type of String can't be null, and even if for every return i added +'h'
. How to deal with null-safety at that case?
Originally the function is:
public String getCodeForCharacter(Character ch, String parentPath) {
if (content == ch) {
return parentPath;
} else {
if (left != null) {
String path = left.getCodeForCharacter(ch, parentPath + 0);
if (path != null) {
return path;
}
}
if (right != null) {
String path = right.getCodeForCharacter(ch, parentPath + 1);
if (path != null) {
return path;
}
}
}
return null;
}
And my full code:
import 'dart:collection';
void main() {
String text = 'where there,s a will there,s a way';
SplayTreeMap? frequencies = countFrequency(text);
frequencies.forEach((key, value) {
print('$key \t $value');
});
var sk = frequencies.values.toList();
print(sk);
List<CodeTreeNode> codeTreeNode = [];
for (String? c in frequencies.keys) {
codeTreeNode.add(new CodeTreeNode.simple(c, frequencies[c]));
}
CodeTreeNode tree = huffman(codeTreeNode);
SplayTreeMap<String, String> codes = SplayTreeMap();
for (String c in frequencies.keys) {
//codes.addAll(c, (value) => tree.getCodeForChar(c, ""));
codes.addAll({c: tree.getCodeForChar(c, "")});
}
codes.forEach((key, value) {
print('$key \t $value');
});
}
SplayTreeMap countFrequency(String text) {
SplayTreeMap? myMap = SplayTreeMap<String, int>();
int tempCount = 0;
// for (int i = 0; i < text.length; i++) {
// String c = text[i];
// int count = myMap[];
// //myMap[int count]
// myMap[c] = count != -1 ? count + 1 : 1;
// }
for (int i = 0; i < text.length; i++) {
String c = text[i];
if (myMap.containsKey(c)) {
//tempCount++;
//myMap[text[i]] = tempCount;
tempCount = myMap[c] + 1;
myMap.update(c, (value) => tempCount);
} else {
myMap[c] = 1;
}
//счетчик = мапа[i] +1;
//заменить эту валью на счетчик
}
return myMap;
}
CodeTreeNode huffman(List<CodeTreeNode> codeTreeNodes) {
while (codeTreeNodes.length > 1) {
codeTreeNodes.sort();
CodeTreeNode left = codeTreeNodes.removeAt(codeTreeNodes.length - 1);
CodeTreeNode right = codeTreeNodes.removeAt(codeTreeNodes.length - 1);
CodeTreeNode parent =
CodeTreeNode.hard(null, right.weight + left.weight, left, right);
codeTreeNodes.add(parent);
}
return codeTreeNodes[0];
}
class CodeTreeNode implements Comparable<CodeTreeNode> {
String? content;
//List<Node> children = [];
int weight;
CodeTreeNode? left;
CodeTreeNode? right;
CodeTreeNode.simple(this.content, this.weight);
CodeTreeNode.hard(this.content, this.weight, this.left, this.right);
// Node(String content, int weight){(this.content, this.weight)
// }
@override
int compareTo(CodeTreeNode other) {
// TODO: implement compareTo
//throw UnimplementedError();
return other.weight - weight;
}
String getCodeForChar(String ch, String parentPath) {
if (content == ch) {
return 'h'+ parentPath;
} else {
if (left != null) {
String path = left.getCodeForChar(ch, parentPath + '0');
if (path != null) {
return 'h'+path;
}
}
if (right != null) {
String path = right.getCodeForChar(ch, parentPath + '1');
if (path != null) {
return 'h'+ path;
}
}
}
return 'hui';
}
}
Inserting you code int DartPad shows two errors.
The method 'getCodeForChar' can't be unconditionally invoked because the receiver can be 'null'.
Fixing this is easy: Insert the bang operator ('!'):
String path = left!.getCodeForChar(ch, parentPath + '0');
See also Working with nullable fields