当前位置: 首页 > news >正文

树的带权路径长度和哈夫曼树

文章目录

  • 前言
  • 树的带权路径长度
  • 哈夫曼树
    • 作用
    • 构建哈夫曼树
    • 编码
  • 总结

前言

树的所有叶子结点的带权路径长度之和,称为树的带权路径长度,英文缩写为 WPL,从百度百科中得到的信息为 “树的带权路径长度(weighted path length of tree)是2018年公布的计算机科学技术名词”,这就有点奇怪了,这个词印象中在大学课本里学过啊,怎么会是2018年的名词呢?难道我穿越了?

我赶紧找来严蔚敏、吴伟民老师编著的《数据结构》翻开来看,在2009年9月第30次印刷的图书的144页中,明确的用加粗字体描述了这样个概念:

树的带权路径长度为树中所有叶子结点的带权路径之和,通常记作 WPL = …

看来我没记错,不是这个百科弄错了,就是2018年重新公布了一次,并不是新的概念,它确实是一个古老的名词了,接下来可以复习一下了。

树的带权路径长度

前面虽然已经给出了定义,可什么是路径,为什么要带权,还要一步步来解释。

路径是指从树的一个结点到另一个结点所走过的部分,路径长度也可以理解为两个结点之间的距离,可以简单理解为路过的结点数,那为什么要带权呢?这和我们生活中的路径一样,并不是距离短的路所花费的时间就少,还要考虑路况、成本等多种因素,而权值就是在特定场景下我们赋予每条路的选择概率。

解释了这几个概念之后我们就可以理解文章开头的定义了,把树的每个叶子结点到根结点的带权路径长度加在一起,就是树的带权路径长度。

哈夫曼树

当使用已知结点作为叶子结点,用其构成的所有树中,带全路径长度最小的树被称为最优二叉树,也就是哈夫曼树。

我们先来计算一下一颗二叉树的带权路径长度,二叉树形态如下:

ROOT
P
2
4
P
7
5

计算二叉树的带权路径长度涉及到树的层数和权值,以上面这个图为例,ROOT 结点所在的层数为0层,往下数字2结点为1层,数字4结点为2层,数字7结点和5结点为3层,方块中的数字代表了该叶子结点的权值,那个这颗树的带权路径长度为:

7 * 3 + 5 * 3 + 4 * 2 + 2 * 1 = 46

那么这是一颗最优树吗?显然不是,因为它的带权路径长度不是最短,其实从计算公式也可以看出一点门道,计算带权路径长度时会用层数乘以权值,因为权值不会变,那么唯一能减小结果的就是调整层数,一个很直观的贪心思路就是把权值大的放在低层,权值小的放在高层,这样就可以减小最后的值,比如调整成这样:

ROOT
P
P
4
2
7
5

这颗树的带权路径长度计算结果为36,比之前的值小了很多:

4 * 2 + 2 * 2 + 7 * 2 + 5 * 2 = 36

其实这还不是一颗最优的树,最优的结构应该是这样:

ROOT
7
P
5
P
2
4

它的带权路径长度计算结果为5,从这可以看出,树的层数高的不一定计算成的带权路径长度就大。

作用

前面说了这么多,那么哈夫曼树有什么作用呢?你应该听说过哈夫曼编码吧,这其实就是哈夫曼树的一个应用,用来找到存放一串字符所需的最少的二进制编码。存放二进制还要单独编码吗?也许你想说什么英文字母不都是编好的吗?

单纯用字母来传递信息有一个问题,那就是会造成浪费,因为每个字母在日常交流中出现的次数并不一样,比如字母 e 是英文中出现频率最高的字母,而字母 z 却出现的很少,所以可以用较短的编码来表示 e 用较长的编码来表示字母 z,这样很直观的就能感觉到同样的信息采取这种方式处理之后会占用更小的空间。

构建哈夫曼树

假设有一段英文文件,我们先统计这个文件中每个字母的出现得到次数,统计如下(别问我这个文件写的什么,我胡诌的(#.#)):

a:19
b:6
c:7
d:3
e:32
f:10
g:21
h:2

因为哈夫曼树使用叶子结点来推导最终的编码,所有我们先用这些数字作为叶子结点:

19
6
7
3
32
10
21
2

接下来记住一个原则,那就是找当前树的根结点和剩余叶子结点的最小的两个值,然后组成新的树杈。


首先,从19、6、7、3、32、10、21、2 中选择频数最小的两个叶子结点,分别为2和3,计算两个结点的和5作为根:

19
6
7
5
3
2
32
10
21

接着,从19、6、7、5、32、10、21 中选择两个最小的结点,分别是根结点5和叶子结点6,计算两个结点的和11作为新的树根:

19
7
11
5
6
3
2
32
10
21

然后,从19、7、11、32、10、21 中选择两个最小的结点,这次都是叶子结点,分别为7和10,计算两个结点的和17形成一颗新的树:

19
11
5
6
3
2
32
17
7
10
21

继续,从 19、11、32、17、21 中选择最小的 11 和 17 这两个树的根结点,计算两个结点的和 28 作为组合树的根结点:

19
11
5
6
3
2
32
17
7
10
28
21

然后,从 19、32、28、21 中选择最小的 19 和 21 这两个叶子结点,计算两个结点的和 40 形成一棵新的树:

11
5
6
3
2
32
17
7
10
28
40
19
21

接下来,从 32、28、 40 中选择最小的 32 和 28 这两个结点,求和 60 构成一棵树,根结点为60:

11
5
6
3
2
17
7
10
28
60
32
40
19
21

最后把剩下的 40 和 60 两个结点连在一起,和为100就得到了一颗哈夫曼树:

11
5
6
3
2
17
7
10
28
60
32
40
19
21
100

按照上面的定义来算,这颗二叉树的带权路径长度为:

WPL = 2 * (32 + 19 + 21) + 4 * (6 + 7 + 10) + 5 * (3 + 2) = 261

其实还有另一种计算带权路径长度的方法,那就是把除根结点以外的所有数字都加起来:

WPL = 60 + 40 + 28 + 32 + 19 + 21 + 11 + 17 + 5 + 6 + 7 + 10 + 3 + 2 = 261

编码

我们用统计数量的字母来替换频数,然后在树的左右指针上分别标上数字就可以得到:

0
1
0
1
0
1
0
1
1
0
0
1
0
1
11
5
b
d
h
17
c
f
28
60
e
40
a
g
100

至此我们就可以给出编码了呀,从根结点走到每个叶子结点路径上经过的0和1就是编码内容,编码表如下:

a–>10
b–>0001
c–>0010
d–>00000
e–>01
f–>0011
g–>11
h–>00001

要想等长编码这8个字母最少需要4个bit,采用哈夫曼编码以后最少用2bit,最多用5bit,这是考虑了出现频率以后的结果,在传输大量数据的时候,采用哈夫曼编码会是一个更优的解决方案。

总结

  • 树的带权路径长度是指树的所有叶子结点的带权路径长度之和,简称WPL
  • 当使用已知结点作为叶子结点,用其构造的所有树中,带全路径长度最小的树被称为最优二叉树,也就是哈夫曼树
  • 哈夫曼树可以用来编码,采用哈夫曼编码后的信息可以可以使空间利用更加高效
  • 哈夫曼树的构造并不是唯一的,相同的权值结点完全可以构造出不同形态的哈夫曼树,甚至连高度都不同
  • 哈夫曼编码还保证了长编码不与短编码冲突的的特点,这个后续有时间我们再聊

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

埋下高昂的头颅,为一飞冲天的壮举积蓄力量,我就在这静静的等,期待你的绽放~

相关文章:

  • 完全图与强连通图的那些坑
  • linux环境下恢复rm误删的文件
  • 记一次使用Valgrind查找解决内存问题的玄幻旅程
  • 网络工具nc的常见功能和用法
  • git常用配置——git show/diff tab 显示宽度
  • Windows设置防火墙允许指定应用正常使用网络
  • 2021年终总结——脚踏实地,为下一次腾飞积蓄力量
  • 通过WindowsStore安装QuickLook小工具方便文件预览
  • linux环境下随时照看服务器进程的ps和top命令
  • 简单梳理下git的使用感受,思考git中最重要的是什么
  • 总结下各种常见树形结构的定义及特点(二叉树、AVL树、红黑树、Trie树、B树、B+树)
  • epoll的LT模式(水平触发)和ET模式(边沿触发)
  • C++可变参数模板的展开方式
  • 恶搞一下std::forward函数
  • C++11新式洗牌std::shuffle与老式洗牌函数std::random_shuffle的区别
  • extjs4学习之配置
  • Git同步原始仓库到Fork仓库中
  • JWT究竟是什么呢?
  • MySQL用户中的%到底包不包括localhost?
  • PHP 7 修改了什么呢 -- 2
  • PHP CLI应用的调试原理
  • redis学习笔记(三):列表、集合、有序集合
  • vuex 笔记整理
  • vue总结
  • 基于组件的设计工作流与界面抽象
  • 排序算法学习笔记
  • 巧用 TypeScript (一)
  • 区块链共识机制优缺点对比都是什么
  • 掌握面试——弹出框的实现(一道题中包含布局/js设计模式)
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • #define MODIFY_REG(REG, CLEARMASK, SETMASK)
  • $.ajax()方法详解
  • (1)(1.11) SiK Radio v2(一)
  • (16)Reactor的测试——响应式Spring的道法术器
  • (delphi11最新学习资料) Object Pascal 学习笔记---第7章第3节(封装和窗体)
  • (js)循环条件满足时终止循环
  • (动手学习深度学习)第13章 计算机视觉---微调
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音
  • (五)MySQL的备份及恢复
  • (五)大数据实战——使用模板虚拟机实现hadoop集群虚拟机克隆及网络相关配置
  • (转)eclipse内存溢出设置 -Xms212m -Xmx804m -XX:PermSize=250M -XX:MaxPermSize=356m
  • (转)Linq学习笔记
  • ***原理与防范
  • .Net mvc总结
  • .Net 访问电子邮箱-LumiSoft.Net,好用
  • .NET 使用配置文件
  • .NET 应用启用与禁用自动生成绑定重定向 (bindingRedirect),解决不同版本 dll 的依赖问题
  • .NET 中选择合适的文件打开模式(CreateNew, Create, Open, OpenOrCreate, Truncate, Append)
  • .NET/C# 编译期间能确定的相同字符串,在运行期间是相同的实例
  • [04] Android逐帧动画(一)
  • [2023年]-hadoop面试真题(一)
  • [DAX] MAX函数 | MAXX函数