DS container adapters <B> priority_queue in Huffman Algorithm 2/99
好问题 👍
在 Huffman 算法里之所以使用 priority_queue
(优先队列/最小堆),主要原因是:
🔑 作用
-
快速找到出现频率最小的两个节点
- Huffman 算法的核心步骤是:反复取出 频率最小的两个节点 合并。
- 如果用普通数组/链表,每次都要排序或遍历,效率会很低。
priority_queue
能保证 O(log n) 时间内取出最小元素。
-
自动维护有序性
- 每次合并后,会把新节点再放回队列。
priority_queue
会自动重新调整结构,继续保持最小堆的性质。- 程序员不需要手动排序。
-
整体复杂度降低
- 用
priority_queue
,建树的复杂度是 O(n log n)(n 为字符种类数)。 - 如果每次手动找最小两个节点,可能退化到 O(n²)。
- 用
📊 举个例子
假设我们有字符频率:
a:5, b:9, c:12, d:13, e:16, f:45
- 第一步:取出最小的
a(5)
和b(9)
→ 合并成节点(14)
。 - 把
(14)
放回priority_queue
,队列会自动调整,保证下次取出的还是频率最小的两个。 - 如此循环,直到只剩一个根节点。
👉 总结:
使用 priority_queue
是为了高效、自动化地取出最小频率节点,保证 Huffman 树的构造在 O(n log n) 时间内完成。
#include <bits/stdc++.h>
using namespace std;struct Node {char ch;int freq;Node *left, *right;Node(char c, int f) : ch(c), freq(f), left(NULL), right(NULL) {}
};struct Compare {bool operator()(Node* a, Node* b) {return /* (1) compare by frequency */;}
};// Recursive function to build Huffman codes
void buildCodes(Node* root, string code, unordered_map<char, string>& huffmanCode) {if (!root) return;if (!root->left && !root->right) {/* (2) assign code to the character */}buildCodes(/* (3) go left */, code + "0", huffmanCode);buildCodes(/* (4) go right */, code + "1", huffmanCode);
}unordered_map<char, string> huffmanEncoding(const string& text) {unordered_map<char, int> freq;for (char ch : text) {/* (5) count frequency */}priority_queue<Node*, vector<Node*>, Compare> pq;for (auto pair : freq) {/* (6) push into priority queue */}while (pq.size() > 1) {Node* left = pq.top(); pq.pop();Node* right = pq.top(); pq.pop();Node* merged = new Node('\0', /* (7) sum of frequencies */);merged->left = left;merged->right = right;pq.push(merged);}Node* root = pq.top();unordered_map<char, string> huffmanCode;buildCodes(root, "", huffmanCode);return huffmanCode;
}int main() {string text = "test huffman";auto codes = huffmanEncoding(text);cout << "Huffman Codes:\n";for (auto pair : codes) {cout << pair.first << " : " << pair.second << "\n";}string encoded = "";for (char ch : text) {/* (8) concatenate Huffman codes */}cout << "\nEncoded string: " << encoded << "\n";return 0;
}
啊,明白了,你问的是这行代码为什么要这么写:
priority_queue<Node*, vector<Node*>, Compare> pq;
我来详细解释一下 ✅
1️⃣ priority_queue 的模板结构
C++ 的 priority_queue
定义是这样的:
template <class T, class Container = vector<T>, class Compare = less<typename Container::value_type>>
class priority_queue;
- T → 队列中存储的元素类型
- Container → 用于存储元素的底层容器,默认是
vector<T>
- Compare → 比较函数对象,默认是
less<T>
(大根堆)
2️⃣ 为什么写成 Node*, vector<Node*>, Compare
-
Node*
- 因为 Huffman 树的每个节点是
Node
类型,我们队列里存的是 指针,所以用Node*
。
- 因为 Huffman 树的每个节点是
-
vector<Node*>
- 指定底层容器是
vector
(priority_queue 默认就是 vector)。 - 也可以用
deque
,但是 vector 更常用。
- 指定底层容器是
-
Compare
-
默认 priority_queue 是大根堆(
less<T>
),取最大值。 -
Huffman 算法需要 取最小频率节点 → 所以自定义
Compare
,让它变成最小堆。 -
Compare 结构定义了:
bool operator()(Node* a, Node* b) {return a->freq > b->freq; // 频率小的排在前面 }
-
3️⃣ 总结
这行代码的意思是:
创建一个 最小堆,存储类型为
Node*
,底层用vector
,比较规则由Compare
决定。
这样每次 pq.top()
都能快速得到 频率最小的节点,正好符合 Huffman 算法的需求。
return a->freq > b->freq;
怎么理解以及为什么这样写。我们一步步来。
1️⃣ Compare 的作用
在 C++ 的 priority_queue
里,Compare
用来 决定堆的顺序。
- 默认是大根堆 (
less<T>
),top()
会返回最大值。 - Huffman 算法需要每次取 频率最小的节点 → 需要最小堆。
2️⃣ 为什么写成 a->freq > b->freq
-
priority_queue
会把 返回 true 的元素排在后面。 -
所以
a->freq > b->freq
的意思是:“如果 a 的频率大于 b 的频率,就让 a 排在 b 后面”
-
这样 堆顶就是最小频率节点,也就是我们每次想取的节点。
3️⃣ 举个例子
假设有三个节点频率:
a:5, b:9, c:12
Compare
会比较节点,5 < 9 → a 排在 b 前面- 9 < 12 → b 排在 c 前面
- 最终堆顶就是 频率最小的 a
每次 pq.top()
就能快速取到最小频率节点,无需排序整个队列。
✅ 总结一句话
a->freq > b->freq
就是在告诉 priority_queue
:把频率小的节点排在堆顶,形成最小堆,方便 Huffman 算法每次取最小节点。