洋澜一签约演唱电影《妈走了,你怎么办》同名主题曲
2026/10/15 15:45:50
哈夫曼树与哈夫曼编码的系统性解析,涵盖了数据结构定义、构建过程(createHTree函数)、编码原理以及实际应用场景。以下是对此内容的进一步整理与补充说明:
#defineMAXLEAFNUM50structnode{charch;// 叶子节点对应的字符(仅叶子节点有效)floatweight;// 权值(频率或概率)intparent;// 父节点索引,0 表示无父节点intlchild;// 左孩子索引,0 表示无左孩子intrchild;// 右孩子索引,0 表示无右孩子}HuffmanTree[2*MAXLEAFNUM-1];// 哈夫曼树存储数组,共 2n-1 个节点typedefstruct{charcode[MAXLEAFNUM];// 存储每个字符的哈夫曼编码字符串intstart;// 编码起始位置(从后往前填,start 指向第一位)}HuffmanCode[MAXLEAFNUM];HuffmanCode数组保存每个叶子节点的最终编码。createHTree函数:构建哈夫曼树步骤详解:
n个字符及其权值填入前n个节点。parent = 0,表示初始状态均无父节点。n+1到2n-1的节点预留作合并用,初始权值设为 0,parent=0。parent == 0的节点中找出两个权值最小的节点s1和s2。i),其:weight = s1.weight + s2.weightlchild = s1,rchild = s2s1.parent = i,s2.parent = i关键点:每次选择两个最小权值节点进行合并 —— 典型贪心策略。
| 编码方式 | 特点 |
|---|---|
| 等长编码 | 每个字符使用相同位数编码(如 ASCII 用 8 位),实现简单但不压缩 |
| 哈夫曼编码 | 变长前缀编码,高频字符短码,低频字符长码,整体平均码长最小 |
编码规则:
0,右分支记为1(或反之)。生成编码方法:
voidcreateHCode(HuffmanTree,H,n){for(inti=1;i<=n;i++){intstart=MAXLEAFNUM-1;intc=i,p=H[i].parent;while(p!=0){if(H[p].lchild==c)code[--start]='0';elsecode[--start]='1';c=p;p=H[p].parent;}HCode[i].start=start;strcpy(HCode[i].code,&code[start]);}}在构建哈夫曼树的过程中,每次需要从当前所有无父节点(即尚未被合并)的节点中选出两个权值最小的节点s1和s2。这是哈夫曼算法的核心操作之一。
使用简单的遍历查找法,在 C 语言中可如下实现:
voidselectMin(structnodeH[],intn,int*s1,int*s2){floatmin1=FLT_MAX,min2=FLT_MAX;*s1=*s2=0;for(inti=1;i<=n;i++){// 跳过已有父节点的节点if(H[i].parent!=0)continue;if(H[i].weight<min1){min2=min1;*s2=*s1;min1=H[i].weight;*s1=i;}elseif(H[i].weight<min2){min2=H[i].weight;*s2=i;}}}说明:
FLT_MAX来自<float.h>,表示浮点最大值。for(inti=n+1;i<=2*n-1;i++){ints1=0,s2=0;selectMin(H,i-1,&s1,&s2);// 在前 i-1 个节点中找最小两个// 设置新节点H[i].lchild=s1;H[i].rchild=s2;H[i].weight=H[s1].weight+H[s2].weight;H[s1].parent=i;H[s2].parent=i;}| 方法 | 描述 | 适用场景 |
|---|---|---|
| 优先队列(最小堆) | 使用最小堆维护所有可用节点,每次取 top 两次,合并后插入新节点 | 大规模数据或动态构造 |
| 排序 + 双指针归并 | 初始按权值排序,之后用两个队列分别保存原始节点和生成的内部节点,利用“单调性”在线性时间内选择最小值 | 高效静态哈夫曼编码 |
| 数组扫描优化 | 添加标记避免重复查找,或缓存候选列表 | 小规模但频繁调用 |
思路: - Q1:存放初始叶子节点,按权值升序排列。 - Q2:存放合并产生的内部节点(按生成顺序,权值自然递增)。 - 每次从 Q1 和 Q2 的队首选两个最小的节点进行合并。优点:总时间复杂度降至 O(n log n) → 实际运行接近 O(n)