考研数据结构赫(哈)夫曼树及其应用

6.12 赫夫曼树及其应用

6.12.1 赫夫曼树

什么叫作赫夫曼树呢?咱们先来看一个例子。算法

过去咱们小学、中学通常考试都是用百分制来表示学科成绩的。这带来了一个弊端,就是很容易让学生、家长,甚至老师本身都以分取人,让分数表明了一切。有时想一想也对,90分和95分也许就只是一道题目对错的差距,但却让两个孩子可能受到彻底不一样的待遇,这并不公平。因而在现在提倡素质教育的背景下,咱们不少的学科,特别是小学的学科成绩都改做了优秀、良好、中等、及格和不及格这样模糊的词语,再也不通报具体的分数。markdown

不过对于老师来说,他在对试卷评分的时候,显然不能凭感受给优良或及格不及格等成绩,所以通常都仍是按照百分制算出每一个学生的成绩后,再根据统一的标准换算得出五级分制的成绩。好比下面的代码就实现了这样的转换。网络

if (a<60)
        b="不及格";
    else if (a<70)
        b="及格";
    else if (a<80)
        b="中等";
    else if (a<90)
        b="良好";
    else
        b="优秀";
复制代码

图6-12-2粗略看没什么问题,但是一般都认为,一张好的考卷应该是让学生成绩大部分处于中等或良好的范围,优秀和不及格都应该较少才对。而上面这样的程序,就使得全部的成绩都须要先判断是否及格,再逐级而上获得结果。输入量很大的时候,其实算法是有效率问题的。 app

图6-12-2ide

若是在实际的学习生活中,学生的成绩在5个等级上的分布规律如表6-12-1所示。性能

表6-12-1学习

那么70分以上大约占总数80%的成绩都须要通过3次以上的判断才能够获得结果,这显然不合理。优化

有没有好一些的办法,仔细观察发现,中等成绩(70~79分之间)比例最高,其次是良好成绩,不及格的所占比例最少。咱们把图6-12-2这棵二叉树从新进行分配。改为如图6-12-3的作法试试看。ui

图6-12-3编码

从图中感受,应该效率要高一些了,到底高多少呢。这样的二叉树又是如何设计出来的呢?咱们来看看赫夫曼大叔是如何说的吧。

6.12.2 赫夫曼树定义与原理

咱们先把这两棵二叉树简化成叶子结点带权的二叉树,如图6-12-4所示。其中A表示不及格、B表示及格、C表示中等、D表示良好、E表示优秀。每一个叶子的分支线上的数字就是刚才咱们提到的五级分制的成绩所占比例数。

图6-12-4

赫夫曼大叔说,从树中一个结点到另外一个结点之间的分支构成两个结点之间的路径,路径上的分支数目称作路径长度。图6-12-4的二叉树a中,根结点到结点D的路径长度就为4,二叉树b中根结点到结点D的路径长度为2。树的路径长度就是从树根到每一结点的路径长度之和。二叉树a的树路径长度就为1+1+2+2+3+3+4+4=20。二叉树b的树路径长度就为1+2+3+3+2+1+2+2=16。

若是考虑到带权的结点,结点的带权的路径长度为从该结点到树根之间的路径长度与结点上权的乘积。树的带权路径长度为树中全部叶子结点的带权路径长度之和。假设有n个权值{w1,w2,…,wn},构造一棵有n个叶子结点的二叉树,每一个叶子结点带权wk,每一个叶子的路径长度为lk,咱们一般记做,则其中带权路径长度WPL最小的二叉树称作赫夫曼树。也有很多书中也称为最优二叉树,我我的以为为了记念作出巨大贡献的科学家,既然用他们的名字命名,就应该要坚持用他们的名字称呼,哪怕“最优”更能体现这棵树的品质也应该只做为别名。

有了赫夫曼对带权路径长度的定义,咱们来计算一下图6-12-4这两棵树的WPL值。

二叉树a的WPL=5×1+15×2+40×3+30×4+10×4=315

注意:这里5是A结点的权,1是A结点的路径长度,其余同理。

二叉树b的WPL=5×3+15×3+40×2+30×2+10×2=220

这样的结果意味着什么呢?若是咱们如今有10000个学生的百分制成绩须要计算五级分制成绩,用二叉树a的判断方法,须要作31500次比较,而二叉树b的判断方法,只须要22000次比较,差很少少了三分之一量,在性能上提升不是一点点。

那么如今的问题就是,图6-12-4的二叉树b这样的树是如何构造出来的,这样的二叉树是否是就是最优的赫夫曼树呢?别急,赫夫曼大叔给了咱们解决的办法。

1.先把有权值的叶子结点按照从小到大的顺序排列成一个有序序列,即:A5,E10,B15,D30,C40。

2.取头两个最小权值的结点做为一个新节点N1的两个子结点,注意相对较小的是左孩子,这里就是A为N1的左孩子,E为N1的右孩子,如图6-12-5所示。新结点的权值为两个叶子权值的和5+10=15。

图6-12-5 3.将N1替换A与E,插入有序序列中,保持从小到大排列。即:N115,B15,D30,C40。

4.重复步骤2。将N1与B做为一个新节点N2的两个子结点。如图6-12-6所示。N2的权值=15+15=30。

图6-12-6

5.将N2替换N1与B,插入有序序列中,保持从小到大排列。即:N230,D30,C40。

6.重复步骤2。将N2与D做为一个新节点N3的两个子结点。如图6-12-7所示。N3的权值=30+30=60。

7.将N3替换N2与D,插入有序序列中,保持从小到大排列。即:C40,N360。

8.重复步骤2。将C与N3做为一个新节点T的两个子结点,如图6-12-8所示。

因为T便是根结点,完成赫夫曼树的构造。

图6-12-7

图6-12-8

此时的图6-12-8二叉树的带权路径长度WPL=40×1+30×2+15×3+10×4+5×4=205。与图6-12-4的二叉树b的WPL值220相比,还少了15。显然此时构造出来的二叉树才是最优的赫夫曼树。 不过现实老是比理想要复杂得多,图6-12-8虽然是赫夫曼树,但因为每次判断都要两次比较(如根结点就是a<80 && a>=70,两次比较才能获得y或n的结果),因此整体性能上,反而不如图6-12-3的二叉树性能高。固然这并非咱们要讨论的重点了。

经过刚才的步骤,咱们能够得出构造赫夫曼树的赫夫曼算法描述。

1.根据给定的n个权值{w1,w2,…,wn}构成n棵二叉树的集合F={T1,T2,…,Tn},其中每棵二叉树Ti中只有一个带权为wi根结点,其左右子树均为空。

2.在F中选取两棵根结点的权值最小的树做为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为其左右子树上根结点的权值之和。

3.在F中删除这两棵树,同时将新获得的二叉树加入F中。

4.重复2和3步骤,直到F只含一棵树为止。这棵树即是赫夫曼树。

6.12.3 赫夫曼编码

固然,赫夫曼研究这种最优树的目的不是为了咱们能够转化一下成绩。他的更大目的是为了解决当年远距离通讯(主要是电报)的数据传输的最优化问题。

好比咱们有一段文字内容为“BADCADFEED”要网络传输给别人,显然用二进制的数字(0和1)来表示是很天然的想法。咱们如今这段文字只有六个字母ABCDEF,那么咱们能够用相应的二进制数据表示,如表6-12-2所示。

表6-12-2

这样真正传输的数据就是编码后的“001000011010000011101100100011”,对方接收时能够按照3位一分来译码。若是一篇文章很长,这样的二进制串也将很是的可怕。并且事实上,不论是英文、中文或是其余语言,字母或汉字的出现频率是不相同的,好比英语中的几个元音字母“a e i o u”,中文中的“的了有在”等汉字都是频率极高。

假设六个字母的频率为A 27,B 8,C 15,D 15,E 30,F 5,合起来正好是100%。那就意味着,咱们彻底能够从新按照赫夫曼树来规划它们。

图6-12-9左图为构造赫夫曼树的过程的权值显示。右图为将权值左分支改成0,右分支改成1后的赫夫曼树。

图6-12-9

此时,咱们对这六个字母用其从树根到叶子所通过路径的0或1来编码,能够获得如表6-12-3所示这样的定义。

表6-12-3

咱们将文字内容为“BADCADFEED”再次编码,对比能够看到结果串变小了。 ■ 原编码二进制串:001000011010000011101100100011 (共30个字符)

■ 新编码二进制串:1001010010101001000111100  (共25个字符)

也就是说,咱们的数据被压缩了,节约了大约17%的存储或传输成本。随着字符的增长和多字符权重的不一样,这种压缩会更加显出其优点。

当咱们接收到1001010010101001000111100这样压缩过的新编码时,咱们应该如何把它解码出来呢?

编码中非0即1,长短不等的话实际上是很容易混淆的,因此若要设计长短不等的编码,则必须是任一字符的编码都不是另外一个字符的编码的前缀,这种编码称作前缀编码

你仔细观察就会发现,表6-12-3中的编码就不存在容易与100一、1000混淆的“10”和“100”编码。

可仅仅是这样不足以让咱们去方便地解码的,所以在解码时,仍是要用到赫夫曼树,即发送方和接收方必需要约定好一样的赫夫曼编码规则。

当咱们接收到1001010010101001000111100时,由约定好的赫夫曼树可知,1001获得第一个字母是B,接下来01意味着第二个字符是A,如图6-12-10所示,其他的也相应的能够获得,从而成功解码。

图6-12-10

通常地,设须要编码的字符集为{d 1 ,d 2 ,…,d n },各个字符在电文中出现的次数或频率集合为{w 1 ,w 2 ,…,w n },以d 1 ,d 2 ,…,d n 做为叶子结点,以w 1 ,w 2 ,…,w n 做为相应叶子结点的权值来构造一棵赫夫曼树。规定赫夫曼树的左分支表明0,右分支表明1,则从根结点到叶子结点所通过的路径分支组成的0和1的序列便为该结点对应字符的编码,这就是赫夫曼编码

相关文章
相关标签/搜索