一、基本概念
最基本的压缩编码方法是赫夫曼编码。赫夫曼编码的定义如下:
![](https://i-blog.csdnimg.cn/blog_migrate/6733464732f9c12c1442ab797ba9632e.png)
二、概念详解
1、赫夫曼树
将一个班级每个学生的百分制成绩根据统一的标准换算成五级分制的成绩,标准如下:
![](https://i-blog.csdnimg.cn/blog_migrate/061624697f61f9a11b4b8131c3009a0f.png)
假设学生的成绩在五个等级上的分布规律如下
![](https://i-blog.csdnimg.cn/blog_migrate/3df8294bd6dccb4a45575bee5e6b3f31.png)
如果用如下的二叉树表示
![](https://i-blog.csdnimg.cn/blog_migrate/2547d065a567c480fbe2d5630686203f.png)
所有的成绩都需要先判断是否及格,再逐级而上得到结果。70分以上大约占总数80%的成绩都需要经过3次以上的判断才可以得到结果。输入量很大的时候,其实算法是由效率问题的。
中等成绩(70-79分之间)比例最高,其次是良好成绩,不及格的所占比例最少。我们把二叉树重新分配如下
![](https://i-blog.csdnimg.cn/blog_migrate/d3c701d8031e428bd3651b853b1a1c46.png)
从图中感觉效率要高一些了,到底高了多少?是不是最优的? 我们先把这两棵树简化成叶子结点带权的二叉树。叶子结点字母表示五级成绩,每个叶子分支线上的数字表示对应成绩所占的比例数。
![](https://i-blog.csdnimg.cn/blog_migrate/a2869594c1d0a8cbf352335ee20c3e11.png)
从树中一个结点到另一个结点之间的分支构成两个结点之间的路径,路径上的分支数目称作路径长度。比如二叉树a中,根结点到结点C的路径长度为4。树的路径长度就是树根到每个结点的路径长度之和。二叉树a的树路径长度就是1+1+2+2+3+3+4+4=20。
如果考虑到带权的结点,结点的带权的路径长度为从该结点到树根之间的路径长度与结点上的权的乘积。树的带权路径长度为树中所有叶节点的带权路径长度之和。假设有n个权值{w1,w2,...,wn},构造一棵有n个叶子结点的二叉树,每个叶子结点带权Wk,每个叶子的路径长度为Lk,其中带权路径长度WPL最小的二叉树称作哈夫曼树,也称为最优二叉树。
二叉树a的WPL=5*1+15*2+40*3+30*4+10*4=315
二叉树b的WPL=5*3+15*3+40*2+30*2+10*2=220
那二叉树b是不是最优二叉树?我们先看下如何构造最优二叉树?
![](https://i-blog.csdnimg.cn/blog_migrate/6616af73c3035bda5abfc487700ee45f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9a16846f8ed52c329878755b44fc6fc8.png)
![](https://i-blog.csdnimg.cn/blog_migrate/8c4e9d8690bf8118a7d97ffb797aeab5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/29c374d6588c1e5d87e0b77cbeeea44b.png)
图6-12-8二叉树的WPL=40*1+30*2+15*3+10*4+5*4=205,此树才是最优的赫夫曼树。
总结,构造赫夫曼树的赫夫曼算法如下:
![](https://i-blog.csdnimg.cn/blog_migrate/2be4c46b6b11306732440ce2a0cb9476.png)
2、赫夫曼编码
赫夫曼研究这种最优树的目的是为了解决当年远距离通信(主要是电报)的数据传送的最优化问题。
我们以网络传输一段文字内容为“BADCADFEED”为例。如果用二进制的数字(0和1)来表示,
![](https://i-blog.csdnimg.cn/blog_migrate/bcfd79f5805b9ed6ae39ed2014a675cf.png)
真正传输的数据就是编码后的“001 000 011 010 000 011 101 100 100 001”。为了看起清楚,我在每个字母的二进制串之间添加了空格。实际上,如果传输一篇很长的文章,这个二进制串就非常大,同时不同字母的出现频率是不相同的。假设这六个字母的频率为
![](https://i-blog.csdnimg.cn/blog_migrate/9a5aceb0da9360648ccfb5ebab0e8997.png)
下图中左边为构造赫夫曼树的过程的权值显示。右边为将权值左分支改为0, 右分支改为1后的赫夫曼树。
![](https://i-blog.csdnimg.cn/blog_migrate/b4d45020e483624ed54329015c373404.png)
此时,我们对这六个字母用其从树根到叶子所经过路径的0或1来编码,得到下表:
![](https://i-blog.csdnimg.cn/blog_migrate/e27a9fd33bed48a73da03c681b8e231a.png)
再次编码为“1001 01 00 101 01 00 1000 11 11 00”。
![](https://i-blog.csdnimg.cn/blog_migrate/4118e184853b0b1ce35da994e98b55c9.png)
对比结果节约了大约17%数据空间。如何方便地解码?必须用到赫夫曼树,即发送方和接收方必须约定好同样的赫夫曼编码规则。
上面新编码二进制串为例,从树根结点出发,按二进制数表示的路径到达叶子节点,解码出字母。后面的二进制再从树根结点出发,以此循环。1001走到叶子节点B,后面的01走到叶子节点A,以此类推。
本文为《大话数据结构》学习笔记,通熟易懂的技术书,购买的请点击下面京东商城的链接:
http://item.jd.com/1026395299.html