使用优先级队列 C++ 将霍夫曼树算法从 O(n^2) 优化到 O(n)
Optimizing the Huffman tree algorithm from O(n^2) to O(n) with priority queue C++
我得到了这个用于组织霍夫曼树的代码片段。
// Build a Huffman tree from a collection of frequencies
template <typename E> HuffTree<E>*
buildHuff(HuffTree<E>** TreeArray, int count) {
heap<HuffTree<E>*,minTreeComp>* forest =
new heap<HuffTree<E>*, minTreeComp>(TreeArray, count, count);
HuffTree<char> *temp1, *temp2, *temp3 = NULL;
while (forest->size() > 1) {
temp1 = forest->removefirst(); // Pull first two trees
temp2 = forest->removefirst(); // off the list
temp3 = new HuffTree<E>(temp1, temp2);
forest->insert(temp3); // Put the new tree back on list
delete temp1; // Must delete the remnants
delete temp2; // of the trees we created
}
return temp3;
}
这是一个非常典型的实现(忽略糟糕的模板化和明显的内存泄漏)。
我应该修改此算法,使其使用优先级队列运行 O(n) 而不是 O(n^2)。我不太确定如何实现这个,但我猜是这样的:
template <typename E>
HuffTree<E>* buildHuff(HuffTree<E>** TreeArray, int count) {
PriorityQueue<HuffTree<E>*, MIN_SORT> forest(count);
for(int i = 0; i < count; i++) {
forest.enqueue(TreeArray[i], TreeArray[i]->weight());
}
HuffTree<E> *tree = NULL;
HuffTree<E> *left, *right = NULL;
while(forest.size() > 0) {
left = forest.dequeue();
if (tree) {
right = tree;
}
else {
right = forest.dequeue();
}
tree = new HuffTree<E>(left, right);
delete left;
delete right;
}
return tree;
}
但是不行。
为了简洁起见,我没有包含引用的 类,但它们的实现非常简单。如果有任何建议可以帮助我朝着正确的方向前进,我将不胜感激。
您的实现始终选择刚刚创建的树作为下一棵树的子树之一。那是不正确的。考虑(有序的)频率:
1, 1, 1, 1, 3
前两个将合并产生频率为 2 的节点,但正确的第二个节点将不包括该节点。
我不明白如何使用优先级队列来生成 O(n) 的解决方案,因为优先级队列需要 O(log n) 来删除最小元素。 (它可以在 O(n) 中构建,但不是你这样做的方式。)
如果您无论如何都要使用 O(n log n) 算法,那么首先只对频率进行排序会更容易。不需要进行进一步的排序,因为生成的节点的生成频率是单调非递减的,因此不需要优先级队列来保持它们的排序。您需要的是(增量地)合并排序的叶子和(在生成时排序的)非叶子。
我得到了这个用于组织霍夫曼树的代码片段。
// Build a Huffman tree from a collection of frequencies
template <typename E> HuffTree<E>*
buildHuff(HuffTree<E>** TreeArray, int count) {
heap<HuffTree<E>*,minTreeComp>* forest =
new heap<HuffTree<E>*, minTreeComp>(TreeArray, count, count);
HuffTree<char> *temp1, *temp2, *temp3 = NULL;
while (forest->size() > 1) {
temp1 = forest->removefirst(); // Pull first two trees
temp2 = forest->removefirst(); // off the list
temp3 = new HuffTree<E>(temp1, temp2);
forest->insert(temp3); // Put the new tree back on list
delete temp1; // Must delete the remnants
delete temp2; // of the trees we created
}
return temp3;
}
这是一个非常典型的实现(忽略糟糕的模板化和明显的内存泄漏)。
我应该修改此算法,使其使用优先级队列运行 O(n) 而不是 O(n^2)。我不太确定如何实现这个,但我猜是这样的:
template <typename E>
HuffTree<E>* buildHuff(HuffTree<E>** TreeArray, int count) {
PriorityQueue<HuffTree<E>*, MIN_SORT> forest(count);
for(int i = 0; i < count; i++) {
forest.enqueue(TreeArray[i], TreeArray[i]->weight());
}
HuffTree<E> *tree = NULL;
HuffTree<E> *left, *right = NULL;
while(forest.size() > 0) {
left = forest.dequeue();
if (tree) {
right = tree;
}
else {
right = forest.dequeue();
}
tree = new HuffTree<E>(left, right);
delete left;
delete right;
}
return tree;
}
但是不行。
为了简洁起见,我没有包含引用的 类,但它们的实现非常简单。如果有任何建议可以帮助我朝着正确的方向前进,我将不胜感激。
您的实现始终选择刚刚创建的树作为下一棵树的子树之一。那是不正确的。考虑(有序的)频率:
1, 1, 1, 1, 3
前两个将合并产生频率为 2 的节点,但正确的第二个节点将不包括该节点。
我不明白如何使用优先级队列来生成 O(n) 的解决方案,因为优先级队列需要 O(log n) 来删除最小元素。 (它可以在 O(n) 中构建,但不是你这样做的方式。)
如果您无论如何都要使用 O(n log n) 算法,那么首先只对频率进行排序会更容易。不需要进行进一步的排序,因为生成的节点的生成频率是单调非递减的,因此不需要优先级队列来保持它们的排序。您需要的是(增量地)合并排序的叶子和(在生成时排序的)非叶子。