17.0、C语言数据结构——浅析赫夫曼树
在数据膨胀、信息爆炸的今天,数据压缩的意义不言而喻;谈到数据亚索,就不能不提赫夫曼(Huffman)编码,赫夫曼编码是首页实用的压缩编码方案,即使在今天的许多知名压缩算法里,依然可以见到赫夫曼编码的影子;
另外,在数据通信中,用二进制给每个字符进行编码时不得不面对一个问题是如何使电文总长最短且不产生二义性;根据字符出现频率,利用赫夫曼编码可以构造出一种不等长的二进制,是编码后的电文长度最短,且保证不产生二义性;
在介绍赫夫曼编码前,给大家看个例子 ->
if(a < 60) {
printf("不及格");
}else if(a < 70) {
printf("及格");
}else if(a < 90) {
printf("良好");
}else {
printf("优秀");
}
由于 优秀 的占比较多占到了 70%,但是优秀的判断在第三个, 70% 都要判断三次效率太低,那么如果把这个判断放到前面第一个或者第二个效率就会提高;
我们先把这两棵二叉树换件成叶子结点带权的二叉树(注:树结点间的连线相关的数叫做权,weight);
结点的路径长度:
- 从根结点到该结点的路径上的连接数;
树的路径长度:
- 树中每个叶子结点的路径长度之和;
结点带权路径长度:
- 结点的路径长度与结点权值的乘积
树的带权路径长度:
- WPL(Weighted Path Length)是树种所有叶子结点的带权路径长度之和;
WPL的值越小,说明构造出来的二叉树性能越优;
构造赫夫曼树的过程:
第一步:在森林中选出两棵根结点的权值最小的二叉树,合并两棵选出的二叉树,增加一个新结点作为新二叉树的根,权值为左右孩子的权值之和;
第二步:在剩下的森林中选出一棵权值最小的结点,如果比刚刚生成的新结点权值小就放左边,反之放右边,该结点与新结点又生成一个新结点,结点权值为左右孩子之和;
.........一直如此递归构造出一棵赫夫曼树
赫夫曼编码可以很有效的压缩数据(通常可以节省 20% ~ 90% 的空间,具体压缩率依赖于数据的特性)
名词解释:定长编码、变长编码、前缀码
- 定长编码:像 ASCII 编码;
- 变长编码:单个编码的长度不一致,可以根据整体出现频率来调节;
- 前缀码:所谓的前缀码,就是没有任何码字是其他码字的前缀;