哈夫曼树构建采用贪心策略:每次合并权值最小的两个节点,借助最小堆高效实现;随后递归生成编码,最后后序遍历释放内存。

一、构建哈夫曼树的贪心策略原理
哈夫曼树的构造基于贪心选择性质:每次从当前可用节点中选取权值最小的两个节点合并,生成新节点,其权值为二者之和。该局部最优选择能保证全局编码长度最短。此过程需借助优先队列(最小堆)高效获取最小权值节点。
1、定义节点结构体,包含字符、权值、左右子节点指针;
2、将所有叶节点(字符及其频次)插入最小堆;
3、当堆中节点数大于1时,重复弹出两个最小权值节点;
4、创建新内部节点,权值为两节点权值之和,左子为较小权值节点,右子为较大权值节点;
5、将新节点重新压入堆中;
6、堆中剩余唯一节点即为哈夫曼树根节点。
二、使用STL priority_queue实现最小堆
C++标准库priority_queue默认为最大堆,需通过自定义比较器反转顺序,使其按权值升序排列,确保每次top()返回权值最小节点。
1、声明比较结构体,重载operator(),返回a.weight > b.weight;
2、定义priority_queue
3、遍历字符频次映射表,为每个字符新建Node对象并push入堆;
4、在合并循环中,调用heap.top()两次获取最小节点,heap.pop()移除;
5、构造父节点后调用heap.push()插入;
6、循环结束后,heap.top()即为根节点指针。
三、手写最小堆类避免STL依赖
为增强可移植性与教学清晰性,可手动实现含sift-down与sift-up逻辑的最小堆类,支持任意Node*元素插入与提取最小值操作,不依赖模板特化或仿函数。
1、声明MinHeap类,内部维护vector
2、实现push(Node* node),将节点追加至末尾并向上调整;
3、实现pop(),交换首尾元素,删除末尾,对新首节点向下调整;
4、实现top(),直接返回data[0];
5、编写siftDown(int i),比较data[i]与其左右子节点权值,若子节点更小则交换并递归;
6、编写siftUp(int i),比较data[i]与其父节点权值,若当前节点更小则交换并递归。
四、递归生成哈夫曼编码字符串
从根节点出发深度优先遍历整棵树,向左走记'0',向右走记'1',到达叶节点时保存当前路径字符串作为该字符的最优二进制编码。
1、定义无返回值递归函数void generateCodes(Node* root, string code, map
2、若root为空,直接返回;
3、若root为叶节点(left == nullptr 且 right == nullptr),执行huffmanCode[root->ch] = code;
4、若root有左子节点,递归调用generateCodes(root->left, code + "0", huffmanCode);
5、若root有右子节点,递归调用generateCodes(root->right, code + "1", huffmanCode);
6、初始调用时传入根节点、空字符串""及空map对象。
五、内存安全释放与析构处理
哈夫曼树动态分配大量Node对象,必须显式释放以防止内存泄漏。采用后序遍历方式逐层delete节点,确保子节点先于父节点被销毁。
1、定义递归析构函数void deleteTree(Node* root);
2、若root为空,直接返回;
3、递归调用deleteTree(root->left);
4、递归调用deleteTree(root->right);
5、执行delete root;
6、主流程在编码生成完毕后,调用deleteTree(root)释放整棵树;
注意:必须在调用deleteTree后将root置为nullptr,避免后续误用悬垂指针。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











