Last updated on May 21, 2025 pm
在哈夫曼编码树的枝叶间,爱意被精准编码,刻进每一段唯一专属的旅程。
核心思想
将高频字符用短编码,低频用长编码,实现数据压缩
代码
二叉哈夫曼树的建树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| struct Node { char ch; int weight; Node *left, *right; };
struct Compare { bool operator()(Node* a, Node* b) { return a->weight > b->weight; } };
Node* buildTree(map<char, int> freqMap) { priority_queue<Node*, vector<Node*>, Compare> pq; for (auto& [ch, w] : freqMap) pq.push(new Node{ch, w, nullptr, nullptr});
while (pq.size() > 1) { Node* a = pq.top(); pq.pop(); Node* b = pq.top(); pq.pop(); Node* parent = new Node{'\0', a->w + b->w, a, b}; pq.push(parent); } return pq.top(); }
|
优先队列
这里用到了小顶堆来取每次最小的weight,需要自定义比较函数。同时定义也需要改一改
priority_queue<Node*,vector<Node*>,Compare>pq;
这里有一篇讲的很清楚的csdn优先队列
哈夫曼编码生成
编码规则:左走记’0’右走记’1’,到叶子时路径就是编码
具体代码:
1 2 3 4 5 6 7 8 9 10 11 12
| void generateCode(Node*root,string path,map<char,string>&codeMap) { if(!root->left&&!root->right) { codeMap[root->ch]=path; return; } generateCode(root->left,path+'0',codeMap); generateCode( root->right,path+'1',codeMao ); }
|
有一篇知乎专栏上的文章,讲的也特别好哈夫曼树
k叉哈夫曼树
当需要更高压缩率的时候需要用到k叉
与二叉的区别:
- 节点结构
子节点要用vector来存储1 2 3 4
| struct KNode { int weight; vector<KNode*> children; };
|
- 虚拟节点补充
当(n-1)%(k-1)!=0的时候要补充虚拟节点1 2 3 4 5
| int m=k-((n-1)%(k-1))-1; for(int i=0;i<m;i++) { pq.push(new Knode{0,{}}); }
|
- 合并逻辑
每次要合并k个节点1 2 3 4 5 6 7 8 9 10 11
| while(pq.size()>1) { KNode*parent=new KNode(0,{}); for(int i=0;i<k;i++) { parent->weight+=pq.top()->weight; parent->children.push_back(pq.top()); pq.pop(); } po.push(parent); }
|
荷马史诗
追逐影子的人,自己就是影子 ⭐⭐⭐
题目
是一道很有感觉的题目。

代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include<iostream> #include<queue> #include<algorithm> #define ll long long using namespace std; struct node { ll weight, height; node(ll w, ll h) :weight(w), height(h) {} }; struct Compare { bool operator()(node a, node b) { if (a.weight != b.weight) return a.weight > b.weight; else return a.height > b.height; } }; int main() { priority_queue<node, vector<node>, Compare>q; ll n, k, ans = 0; cin >> n >> k; for (int i = 1; i <= n; i++) { ll w; cin >> w; q.push(node(w,1)); } while ((q.size() - 1) % (k - 1) != 0) { q.push(node(0,1)); } while (q.size() > 1) { ll h = -1, w = 0; for (int i = 1; i <= k; i++) { node temp = q.top(); q.pop(); h = max(h, temp.height); w += temp.weight; } ans += w; q.push(node(w,h+1)); } cout << ans << endl; cout << q.top().height - 1; return 0; }
|
作为我洛谷做的第一道蓝题,it deserves!💌
演好自己的角色
和这句话相似地,库切曾经说过:你内心肯定有着某种火焰🔥,能把你和他人区分开来。
演好自己的角色,我的生命里才能始终跳动着灵魂的火焰。🎆