Search code examples
javadartbinary-treedart-null-safetyhuffman-code

Huffman algorithm, building code tree dart null-safety java reference


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';
  }
}

Solution

  • 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