哈夫曼树及哈夫曼编码(考试常考版)

哈夫曼树的基本概念

哈夫曼树的定义是对一组具有确定权值的叶子节点,选出最小带权路径长度的二叉树为哈夫曼树(WPL最小),也称最优二叉树

哈夫曼算法的实现

注意:哈夫曼树在构造时选择两个最小的权值点,默认小的在左边大的在右边,但实际上并没有硬性规定,可以互换,对长度没有影响,但本文默认小的在左边大的在右边
1.对权值节点排序,在n个权值节点中选出两个最小的,这两个节点作为左右子树形成一棵新的二叉树,根节点的值是左右子树权值的加和
2.将原序列中最小的两个权值删除,将新的权值加入到序列中(原最小两个权值的和),并排序
3.不断重复1和2步骤,直至只剩下一棵树**(结束的表示是序列只剩1个节点值)**,此树为所构造的哈夫曼树
下面用图说明哈夫曼树的构造过程,给定权值1 5 2 6 10 7,要求构造出哈夫曼树
初始状态为
在这里插入图片描述

1.将权值进行排序得到1 2 5 6 7 10,选出权值最小的两个节点分别是1和2,将1和2作为左右子树生成一棵二叉树,根节点值为3
2.将最小的两个节点(1,2删除),将节点3加入到序列中,此时序列为3 5 6 7 10,即
在这里插入图片描述
3.由于序列中的所有节点(剩余5个)大于1个,继续循环上述1和2过程,此时序列为3 5 6 7 10,将权值最小的两个节点3和5作为左右子树生成新的一棵二叉树,根节点为3+5=8
4.将3和5节点删除,将节点8加入到序列中,重新排序,此时序列为6 7 8 10,如下图
在这里插入图片描述
5.由于并没有消耗完序列中的所有节点(剩余4个)大于1个,继续循环上述1和2过程,此时序列为6 7 8 10,将权值最小的两个节点6和7作为左右子树生成新的一棵二叉树,根节点为6+7=13
6.将6和7节点删除,将节点13加入到序列中,重新排序,此时序列为8 10 13,如下图
在这里插入图片描述
7.由于序列中的所有节点(剩余3个)大于1个,继续循环上述1和2过程,此时序列为8 10 13,将权值最小的两个节点8和10作为左右子树生成新的一棵二叉树,根节点为8+10=18
8.将6和7节点删除,将节点18加入到序列中,重新排序,此时序列为13 18,如下图
在这里插入图片描述
9.由于序列中的所有节点(剩余2个)大于1个,继续循环上述1和2过程,此时序列为13 18,将权值最小的两个节点13和18作为左右子树生成新的一棵二叉树,根节点为13+18=31
10.将13和18节点删除,将节点31加入到序列中,此时序列为31,如下图
在这里插入图片描述
11.此时序列只剩1个元素,循环结束,所生成的树即为哈夫曼树。

哈夫曼编码

在通信传送时,数据表现为0和1的二进制形式。为了提高传输的速度,通常会进行数据压缩。同时,要保证编码不存在二义性。哈夫曼编码符合上述要求,能达到较优的编码方式,其原理就是自底向上构建哈夫曼树
例:假设某报文由{‘l’,‘m’,‘y’,‘z’,‘j’,‘h’}六个字符组成,每个字符出现的频率分别是{0.24,0.16,0.2,0.08,0.02,0.3},为这6个字符设计哈夫曼编码

数据预处理

首先可以将字符出现的频率转换为整数,即每个概率乘100,得到相应权值

字符权值
l24
m16
y20
z8
j2
h30
构造哈夫曼树

此时l字符对应权值为24,m字符对应权值为16.等,得到6个节点的权值后,按照上文讲到的方法构造哈夫曼树(不断循环方式1和方式2直至只剩下一棵树),具体细节不再赘述。
生成的哈夫曼树如下:
在这里插入图片描述

按照哈夫曼编码的规则,每个根节点的左子树编码为0 每个根节点的右子树编码为1
根据上述规则可以生成每个字符(即出现频率的节点 如l为24的节点为01)对应的编码

字符编码
l01
m101
y00
z1001
j1000
h11

用哈夫曼编码得到的序列长度应为24 * 2+16 * 3 + 20 * 2 + 8 * 4 + 2 * 4 + 30 * 2 = 236
而利用等长编码由于字符数为6位,需要用3位二进制数表示,因此序列长度为300
可以看到哈夫曼编码的序列明显小于等长编码得到的序列,比例为236/300。

  • 14
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
哈夫曼树是一种重要的数据结构,它常常被用来进行数据压缩和编码。下面是哈夫曼树的构造及字符编码的C语言实现: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_NODE_NUM 1000 // 哈夫曼树节点最大数目 #define MAX_CODE_LEN 1000 // 哈夫曼编码最大长度 // 哈夫曼树节点结构体 typedef struct { int weight; // 权重 int parent, lchild, rchild; // 父亲节点、左儿子节点、右儿子节点 } HTNode; // 哈夫曼编码结构体 typedef struct { char ch; // 字符 char code[MAX_CODE_LEN]; // 编码 } HCode; // 建立哈夫曼树,并返回根节点的下标 int CreateHT(HTNode ht[], int n) { int i, j, k, x1, x2, min1, min2; for (i = 0; i < 2 * n - 1; i++) { ht[i].parent = ht[i].lchild = ht[i].rchild = -1; } for (i = n; i < 2 * n - 1; i++) { min1 = min2 = 0x7fffffff; // 设置最大值 x1 = x2 = -1; for (j = 0; j < i; j++) { if (ht[j].parent == -1) { if (ht[j].weight < min1) { min2 = min1; x2 = x1; min1 = ht[j].weight; x1 = j; } else if (ht[j].weight < min2) { min2 = ht[j].weight; x2 = j; } } } ht[x1].parent = i; ht[x2].parent = i; ht[i].lchild = x1; ht[i].rchild = x2; ht[i].weight = ht[x1].weight + ht[x2].weight; } return 2 * n - 2; } // 生成哈夫曼编码 void CreateHCode(HTNode ht[], HCode hcd[], int n) { char cd[MAX_CODE_LEN]; int i, j, c, p; for (i = 0; i < n; i++) { hcd[i].ch = i + 'a'; // 假设字符集为26个小写字母 cd[n - 1] = '\0'; c = i; while (ht[c].parent != -1) { p = ht[c].parent; if (ht[p].lchild == c) { cd[strlen(cd) - 1] = '0'; } else { cd[strlen(cd) - 1] = '1'; } c = p; strcat(cd, " "); } strcpy(hcd[i].code, strrev(cd)); } } int main() { int n, i, root; HTNode ht[MAX_NODE_NUM]; HCode hcd[MAX_NODE_NUM]; printf("请输入字符集的大小:"); scanf("%d", &n); printf("请输入各个字符的权重:"); for (i = 0; i < n; i++) { scanf("%d", &ht[i].weight); } root = CreateHT(ht, n); CreateHCode(ht, hcd, n); printf("字符\t权重\t哈夫曼编码\n"); for (i = 0; i < n; i++) { printf("%c\t%d\t%s\n", hcd[i].ch, ht[i].weight, hcd[i].code); } return 0; } ``` 以上程序中,`CreateHT`函数用于建立哈夫曼树,`CreateHCode`函数用于生成哈夫曼编码。在这个例子中,我们假设字符集为26个小写字母。对于每个字符,我们首先计算它的权重。然后利用`CreateHT`函数建立哈夫曼树,再利用`CreateHCode`函数生成哈夫曼编码。最后输出每个字符的权重和哈夫曼编码。 需要注意的一点是,哈夫曼编码是从叶子节点到根节点的,因此我们需要将最后得到的编码字符串反转。这里我们使用了一个`strrev`函数,它可以将一个字符串反转。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值