赫夫曼树+赫夫曼编码小结

数据结构 同时被 2 个专栏收录
3 篇文章 0 订阅
18 篇文章 0 订阅

赫夫曼树

赫夫曼树定义与原理

从树中一个节点到另一个节点之间的分支构成两个结点之间的路径,路径上的分支数目称做路径长度

图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。

如果考虑到带权的结点,结点的带权的路径长度为从该结点到树根之间的路径长度与结点上权的乘积。树的带权路径长度为树中所有叶子结点的带权路径长度之和,则其中带权路径长度WPL最小的二叉树称做赫夫曼树

有了赫夫曼对带权路径长度的定义,我们可以计算一下上图这两棵树的WPL值。

二叉树a的WPL=5X1+15X2+40X3+30X4+10X4=315

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

二叉树b的WPL=5X3+15X3+40X2+30X2+10X2=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。

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

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

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

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

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

  8. 重复步骤2。将C与N3作为一个新结点T的两个子结点,如图6-12-8所示。由于T即是根结点,完成赫夫曼树的构造。

此时的图6-12-8二叉树的带权路径长度WPL=40X1+30X2+15X3+10X4+5X4=205。与图6-12-4的二叉树b为WPL值220相比,还少了15。显然此时构造出来的二叉树才是最优的赫夫曼树。

通过刚才的步骤,我们可以得出构造赫夫曼树的赫夫曼算法描述。

  1. 根据给定的n个权值{w1,w2,…,wn}构成n棵二叉树的集合F={T1,T2,…,Tn},其中每棵二叉树T1中只有一个带权为w1根结点,其左右子树均为空。
  2. 在F中选区两棵根结点的权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为左右子树上根结点的权值之和。
  3. 在F中删除这两棵树,同时将新得到的二叉树加入到F中。
  4. 重复2和3步骤,直到F只含一棵树为止。这棵树便是赫夫曼树。

赫夫曼编码

赫夫曼研究这种最优树的目的是为了解决当年远距离通信(主要是电报)的数据传输的最优化问题。

比如我们有一段文字内容为"BADCADFEED"要网络传输给别人,显然用二进制的数字(0和1)来表示是很自然的想法。我们现在这段文字只有六个字母ABCDEF,那么我们可以用相应的二进制数据表示,如表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后的赫夫曼树。

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

我们将文字内容为"BADCADFEED"再次编码,对比可以看到结果串变小了。

  • 原编码二进制串:0010000110100000111011001000011(共30个字符)
  • 新编码二进制串:1001010010101001000111100(共25个字符)

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

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

编码中非0即1,长度不等的话其实是很容易混淆的,所以若要设计长短不等的编码,则必须是任一字符的编码都不是另一个字符的编码的前缀,这种编码称做前缀编码

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

可仅仅是这样不足以让我们去方便地解码的,因此在解码时,还是要用到赫夫曼树,即发送方和接收方必须要约定好同样的赫夫曼编码规则。

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

一般地,设需要编码的字符集为{d1,d2,…,dn},各个字符在电文中出现的次数或频率集合为{w1,w2,…,wn},以d1,d2,…dn作为叶子结点,以w1,w2,…,wn作为相应叶子结点的权值来构造一棵赫夫曼树。规定赫夫曼树的左分支代表0,右分支代表1,则从根结点到叶子结点所经过的路径分支组成的0和1序列便为该结点对应字符的编码,这就是赫夫曼编码

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值