Dart实现Huffman算法:getCodeForChar函数空安全问题求解
Dart实现Huffman算法时的空安全问题
我把Java版的Huffman算法改成了Dart版本,但在getCodeForChar函数上碰到了空安全问题。这个函数返回类型是String,不允许为null,哪怕我给所有返回值都加了+'h'还是报错,该怎么解决?
原Java实现的函数
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; }
我的Dart完整代码
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'; } }
问题分析与解决
你的核心问题有两个:
- 空安全调用问题:Dart中
left和right是可空类型CodeTreeNode?,直接调用left.getCodeForChar()会触发空安全错误,必须先确保非空才能调用。 - 逻辑冗余与错误处理:原Java返回
null表示未找到字符,但Dart要求返回非空String,用'hui'兜底不符合业务逻辑,且会破坏编码正确性。
修复步骤:
1. 修复可空节点的调用方式
对已判断非空的left/right使用空断言!,告诉编译器此时变量非空:
if (left != null) { String path = left!.getCodeForChar(ch, parentPath + '0'); return path; }
2. 优化返回逻辑,避免无意义兜底
因为Huffman树是基于输入文本的字符构建的,要查找的字符必然存在,所以最后分支可以抛出异常代替兜底值:
throw StateError('Character "$ch" does not exist in the Huffman tree');
3. 完整修复后的getCodeForChar函数
String getCodeForChar(String ch, String parentPath) { if (content == ch) { return parentPath; // 移除不必要的'h',还原原逻辑的编码路径 } if (left != null) { return left!.getCodeForChar(ch, parentPath + '0'); } if (right != null) { return right!.getCodeForChar(ch, parentPath + '1'); } // 理论上不会走到这里,抛出异常标记异常情况 throw StateError('Character "$ch" does not exist in the Huffman tree'); }
4. 其他代码小修复
- 明确
countFrequency的返回类型,避免类型警告:
SplayTreeMap<String, int> countFrequency(String text) { SplayTreeMap<String, int> myMap = SplayTreeMap(); // 原有逻辑不变 }
main中frequencies无需声明为可空:
SplayTreeMap<String, int> frequencies = countFrequency(text);
内容的提问来源于stack exchange,提问作者paprikaparty33
相关产品推荐
相关产品推荐

