我想使用Java Stream从输入字符串构建Huffman tree。
这就是我现在的做法。
使用所有需要的构造函数的类MyNode:
public static class MyNode {
Character value;
MyNode left;
MyNode right;
long freq;
...
}
读取一行并获取MyNodes列表:
Scanner scan = new Scanner(System.in);
String input = scan.next();
List<MyNode> listOfNodes = input.chars().boxed()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream().sorted(Comparator.comparingLong(Map.Entry::getValue))
.map(x -> new MyNode((char)x.getKey().intValue(), x.getValue()))
.collect(Collectors.toList());
这个while
循环我想用Stream中的内容替换:
while (listOfNodes.size() > 1) {
MyNode first = listOfNodes.get(0);
MyNode second = listOfNodes.get(1);
listOfNodes.remove(first);
listOfNodes.remove(second);
listOfNodes.add(new MyNode(first.freq + second.freq, first, second));
listOfNodes.sort(Comparator.comparingLong(MyNode::getFreq));
}
在while循环中,我构建了这样的
树第一个想法是使用Stream reduce,但是我需要在每次reduce之后对结果列表进行排序。
答案 0 :(得分:2)
这不是一项受益于使用Stream API的任务。不过,有一些方法可以改进它。
仅为了插入单个元素而对整个列表进行排序,会产生不必要的开销。由于列表是按照开头排序的,因此您可以使用二进制搜索来有效地找到正确的插入位置,以便列表保持排序:
while(listOfNodes.size() > 1) {
MyNode first = listOfNodes.remove(0), second = listOfNodes.remove(0);
MyNode newNode = new MyNode(first.freq + second.freq, first, second);
int pos = Collections.binarySearch(listOfNodes, newNode,
Comparator.comparingLong(MyNode::getFreq));
listOfNodes.add(pos<0? -pos-1: pos, newNode);
}
请注意,您可以通过撤消订单来提高此代码的效率,以便从列表末尾删除(实际上这将是ArrayList
)。
但更好的选择是使用一个数据结构,该数据结构按开头排序,例如
PriorityQueue<MyNode> queueOfNodes = input.chars().boxed()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet().stream()
.map(x -> new MyNode((char)x.getKey().intValue(), x.getValue()))
.collect(Collectors.toCollection(
() -> new PriorityQueue<>(Comparator.comparingLong(MyNode::getFreq))));
MyNode result = queueOfNodes.remove();
while(!queueOfNodes.isEmpty()) {
MyNode second = queueOfNodes.remove();
queueOfNodes.add(new MyNode(result.freq + second.freq, result, second));
result = queueOfNodes.remove();
}