C++从零构建哈夫曼树需用最小堆贪心合并频率最小的两子树,以得最优编码;用unordered_map统计字符频次,shared_ptr管理节点内存,自定义lambda比较器确保堆正确排序,空输入或单字符需特殊处理。

用C++从零构建哈夫曼树并生成最优二进制编码,需严格遵循贪心策略:每次合并频率最小的两棵子树,确保高频字符编码短、低频字符编码长,最终使加权路径长度WPL最小。
准备字符频率映射与优先队列容器
定义字符到频次的映射关系,使用unordered_map存储输入样本中各字符出现次数;同时声明一个最小堆,元素类型为指向HuffmanNode的智能指针,比较规则按节点权重升序排列。
这一步不能用vector手动排序后取首尾——因为后续每轮合并都会产生新节点,必须靠堆动态维护最小两个候选者。
声明优先队列时,需自定义lambda比较器,捕获方式用[ ]而非[&],避免悬空引用。
立即学习“C++免费学习笔记(深入)”;
构建哈夫曼树的核心贪心循环
当优先队列中节点数大于1时,执行以下操作:
① 弹出权重最小的节点left = pq.top(); pq.pop();
② 再弹出次小节点right = pq.top(); pq.pop();
③ 创建新父节点parent,其权重为left->weight + right->weight,left设为左子,right设为右子;
④ 将parent压入优先队列;
循环结束时,队列只剩唯一根节点,即哈夫曼树的root。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
注意:若输入只有一种字符,优先队列初始大小为1,该循环不执行,需单独处理——此时编码应为单个'0'或'1',否则生成空字符串导致解码失败。
递归遍历生成二进制编码表
从root出发,向左走记'0',向右走记'1',到达叶子节点时将路径字符串存入map
递归函数需传入当前节点指针和当前路径字符串;遇到空节点立即返回,避免段错误。
这一步操作起来很简单,直接把文件拖进去就行。
方法一:使用shared_ptr管理节点内存
定义HuffmanNode结构体,含weight、ch、left、right成员;所有节点均用make_shared创建,入队出队全程使用shared_ptr,无需手动delete。
【必须在构造函数中初始化weight为0,否则未显式赋值时可能为随机值】
方法二:手写最小堆比较器类
定义CompareNode类,重载operator(),接收两个shared_ptr
不要用function对象替代——编译期绑定比运行时调用更快,尤其在高频合并场景下。
方法三:支持重复字符与空格的输入解析
读取输入字符串时用getline(cin, s),而非cin >> s,否则空格和制表符会被跳过;统计频次时遍历s每个char,包括'\n'和' '。
若输入为空字符串,则编码表为空,程序应输出提示并退出,不尝试建树。

















