C++实现哈夫曼树的最优编码构建 _ 贪心算法核心逻辑实现【源码】

夜芳小哥_6122

夜芳小哥_6122

2026-04-30

454人浏览

原创

哈夫曼树构建必须用priority_queue实现小顶堆,时间复杂度o(n log n);编码表生成须用dfs递归,避免bfs拼接错误;字符统计需用unsigned char防符号扩展;同频节点顺序不影响最优性但影响编码一致性。

c++实现哈夫曼树的最优编码构建 _ 贪心算法核心逻辑实现【源码】

哈夫曼树构建必须用 priority_queue,别手写排序队列

手动维护一个按权值升序排列的节点列表,在每次合并后重新插入、再排序,不仅代码冗长,而且时间复杂度会退化到 O(n²)。C++ 标准库的 priority_queue(默认大顶堆)配合自定义比较器,能天然支持小顶堆语义,让每次取最小两个节点的操作稳定在 O(log n)。

常见错误是直接用 priority_queue<node></node> 却没重载 operator,或误以为默认就是小顶堆——其实它是大顶堆,必须显式传入 <code>greater 或自定义仿函数:

struct Node {
    int freq;
    char ch;
    Node* left;
    Node* right;
    Node(int f, char c) : freq(f), ch(c), left(nullptr), right(nullptr) {}
};
auto cmp = [](const Node* a, const Node* b) { return a->freq > b->freq; };
priority_queue<node vector>, decltype(cmp)> pq(cmp);
</node>
  • 节点指针入队,避免拷贝;出队后记得 delete 释放(除非用智能指针)
  • 频率相同时无需额外排序逻辑——哈夫曼算法对同频节点顺序不敏感,不影响最优性
  • 若输入只有 1 个字符(如压缩单字符文件),需单独处理:直接生成编码 "0",不能进 while 循环

编码表生成必须用 DFS 递归,BFS 容易漏位或错序

从根到叶子的路径决定编码(左 0 右 1),DFS 天然携带路径状态,每到叶子就存下当前 string 编码;BFS 虽可实现,但需同步维护每个节点对应的编码字符串,容易在入队时拼接错误,尤其遇到空子节点时边界混乱。

递归写法简洁且不易错,关键点在于:参数传引用避免字符串重复拷贝,叶子判断用 !node->left && !node->right,而非只判 node->ch != '<p>递归写法简洁且不易错,关键点在于:参数传引用避免字符串重复拷贝,叶子判断用 <code>!node->left && !node->right,而非只判 node->ch != '\0'(内部节点也可能被赋值):

'(内部节点也可能被赋值):

C++ Code Review Master
C++ Code Review Master

组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。

下载
void generateCodes(Node* node, string code, unordered_map<char string>& codes) {
    if (!node) return;
    if (!node->left && !node->right) {
        codes[node->ch] = code;
        return;
    }
    generateCodes(node->left, code + "0", codes);
    generateCodes(node->right, code + "1", codes);
}
</char>
  • 初始调用为 generateCodes(root, "", codes),空字符串起步
  • 若字符集含 '\0'(比如二进制数据),不能用 char 做 key,应改用 unsigned char 或 int
  • 编码表大小严格等于叶节点数,即不同字符数;重复字符在建树前已统计合并,不会多映射

贪心选择性质在这里很“脆”,别在中间改频率或重排

哈夫曼算法的贪心本质是:每一步都选当前可用的两个最小频次节点合并,新节点频次为二者之和,并放回候选集。这个“当前可用”意味着——一旦某节点被取出,就不能再参与本轮比较;合并后的新节点必须参与后续轮次。任何试图跳过最小、或提前把高频节点拉进来合并的操作,都会破坏最优子结构。

  • 典型错误:遍历 priority_queue 查最小值(它不支持遍历),或用 top() 取两次却不 pop(),导致重复使用同一节点
  • 正确流程只能是:pop 两次 → 合并 → push 新节点 → 直到队列只剩 1 个
  • 若输入频次含负数(虽不合理),priority_queue 仍会按数值排,但哈夫曼理论要求权值非负,否则无意义
  • 浮点频率?不行。标准哈夫曼要求整数权值(或可缩放为整数),否则 double 比较可能因精度失效

实际编码时字符类型要小心 signed char 的符号扩展

读文件统计频次时,如果直接用 char c = f.get(),在某些平台(如 x86_64 Linux GCC)下,char 默认是 signed,当读到字节 0xFF 时会变成 -1,作为 unordered_map 的 key 就和 (unsigned)255 冲突。结果就是 0x80~0xFF 的字符全被映射到负数区间,编码表缺失一半。

  • 安全做法:统一用 unsigned char 存储和索引,例如 freq[static_cast<unsigned char>(c)]++</unsigned>
  • 输出编码字符串时,也需用 static_cast<unsigned char>(ch)</unsigned> 查表,避免符号截断
  • 如果只处理 ASCII 文本(0–127),这个问题不暴露,但一处理 PNG、ZIP 等二进制数据就立刻崩

构建完成的哈夫曼树本身不保存字符集顺序,也不隐含字典序;编码是否唯一取决于建树过程中对同频节点的左右分配策略——这在实际压缩中无关紧要,但调试时若发现相同输入产生不同编码,大概率是 priority_queue 对同频指针的地址比较引入了不确定序,加个稳定比较(如比指针地址)就能复现一致结果。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
c++和c语言的区别有哪些
c++和c语言的区别有哪些

c++和c语言的区别:1、面向对象编程(OOP)支持不同;2、新增特性不同;3、标准库不同;4、编译方式不同;5、命名空间不同等等。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.14

2228

9

c++和python学习顺序推荐
c++和python学习顺序推荐

一般建议先学习C++,再学习Python,因为这样可以逐步从较为底层的编程语言向更高级的语言过渡。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

999

6

python和c++学习性价比分析
python和c++学习性价比分析

Python易于学习,广泛应用于Web开发、数据科学和人工智能等领域,但性能较低。C语言性能高,适用于对性能要求较高的场景,如游戏开发和系统编程,但学习曲线陡峭,错误处理复杂。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

427

5

c语言和c++一样吗
c语言和c++一样吗

c语言和c++是两种不同的编程语言,虽然有相似之处,但存在显著差异。c语言专注于过程式编程和系统级开发,以简洁、高效著称。c++作为c语言的超集,引入了面向对象编程,增强了代码组织和管理能力,但学习曲线也更陡峭。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

307

5

c语言和c++先学哪个好
c语言和c++先学哪个好

初学者选择学习c语言还是c++语言,需要根据个人学习目标、背景以及编程兴趣和预期应用方向来决定。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

406

5

c语言和c++的区别和联系
c语言和c++的区别和联系

c语言和c++是计算机科学领域应用广泛的编程语言。虽然它们有着相似的基础,但它们在语言类型、语法功能和内存管理方面存在着显著差异。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

580

5

c++软件中文更改教程
c++软件中文更改教程

对于 ide,可通过打开设置,找到语言设置,选择中文,并保存更改。对于非 ide 应用程序,可查找设置或选项,选择语言设置,更改为中文,并保存更改。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.21

1389

9

python和java和c++学习性价比分析
python和java和c++学习性价比分析

Python以其易学性、丰富的库和活跃的社区而著称,适合数据科学、人工智能和Web开发。Java以其跨平台性、企业级应用开发和Android应用开发而闻名。C++以其底层控制能力、高效性能和游戏开发而著称。选择哪种语言取决于个人兴趣、职业方向和特定需求。想了解更多python和java和c++的相关内容,可以阅读本专题下面的文章。

2024.03.22

1197

7

c++和c语言学习顺序推荐
c++和c语言学习顺序推荐

对于初学者,建议先学习C语言,掌握编程基础后再转入C++,便于理解面向对象编程概念。有编程经验者可直接学习C++,快速接触高级编程技术。想了解更多c++和c语言的相关内容,可以阅读本专题下面的文章。

2024.03.25

1325

9

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Fitten Code官方手册
Fitten Code官方手册

共0课时 | 0人学习

CodeGeex使用手册
CodeGeex使用手册

共0课时 | 0人学习

通义灵码手册
通义灵码手册

共0课时 | 0人学习