WPL 和哈夫曼树学习
哈夫曼树,又称最优二叉树,是一棵带权值路径长度(WPL,Weighted Path Length of Tree)最短的树,权值较大的节点离根更近。编码
首先介绍一下什么是 WPL,其定义是树的全部叶结点的带权路径长度之和,称为树的带权路径长度
,公式为 WPL = W1 * L1 + W2 * L2 + W3 * L3 + ... + Wn * Ln。spa
下面是个最简单且最直观的案例,经过实际案例可以更清晰的表示 WPL 和哈夫曼树。code
百分制的成绩转换成五分制的成绩,伪代码以下:blog
if (score < 60) grade = 1; else if (score < 70) grade = 2; else if (score < 80) grade = 3; else if (score < 90) grade = 4; else grade = 5;
经过这个规则,能够生成一棵断定树,以下:字符串
score < 60 / \ grade = 1 score < 70 / \ grade = 2 score < 80 / \ grade = 3 score < 90 / \ grade = 4 grade = 5
根据断定树能够看出:对于 60 分如下的分数,只须要一次就可以给出结果;对于 60~70 分的成绩,须要判断 2 次给出结果;对于 70~80 的成绩则须要判断 3 次,依次类推。字符编码
那么问题来了,绝大多数成绩处于 80~90 分,只有少数成绩处于 60 分如下及 90 分以上,那判断的次数是否是有点多呢?其中这个"绝大多数"和"少数"就是一个权值的概念了。class
好比成绩分布以下:二叉树
| 成绩 | 0~59 | 60~70 | 70~80 | 80~90 | 90~100 | | 比例 | 0.05 | 0.15 | 0.30 | 0.40 | 0.10 |
那么判断次数等于: WPL = 0.05 * 1 + 0.15 * 2 + 0.30 * 3 + 0.40 * 4 + 0.10 * 5 = 3.35搜索
这里产生一个想法:假如把 80~90 的判断拿到最前面,不就可以减小大部分红绩的计算路径了吗?
修改后的断定树应该是这样的
score < 80 / \ score < 70 score < 90 / \ / \ score < 60 grade = 3 grade = 4 grade = 5 / \ grade = 1 grade = 2
其判断次数等于:WPL = 0.40 * 2 + 0.30 * 2 + 0.10 * 2 + 0.15 * 3 + 0.05 * 3 = 2.2
经过上面的案例,就可以得出结论,哈夫曼树可以根据节点的查找频率来构造更有效的搜索树,是 WPL 最小的树。
哈夫曼树的构造能够理解为将权值最小的两棵二叉树合并,这个树的权值等于 2 个子树的和。
关于如何选取两个权值最小的二叉树,可使用最小堆实现,复杂度是 O(N log N)。
好比权值:{1,2,3,4,5},能够得出:
15 // 输出 15 / \ 6 9 // 取出 4,5 ;输出 9,得出 {6,9} / \ / \ 3 3 4 5 // 取出 3,3 ;输出 6,得出 {6,4,5} / \ 1 2 // 取出 1,2 ;输出 3,得出 {3,3,4,5}
计算如下 WPL = 2 * 3 + 2 * 4 + 2 * 5 + 3 * 1 + 3 * 2 = 33
哈夫曼树的特色:
哈夫曼编码用于数据存储中作压缩,以下案例:
给定一段包含 50 个字符的字符串,由 {a,b,c,d,e,f}构成,且每一个字符出现次数不一样,会有以下几种存储方式。
第三种即可以使用哈夫曼树来实现,假如给定:
| 字符 | a | b | c | d | e | f | | 次数 | 18 | 4 | 16 | 1 | 1 | 10 |
构成哈夫曼树:
50 0/ \1 a(18) 32 0/ \1 c(16) 16 0/ \1 6 f(10) 0/ \1 2 b(4) 0/ \1 d(1) e(1)
因此: a:0; b:1101; c:10; d:11000; e:11001; f:111 。
长度为: 1 * 18 + 4 * 4 + 16 * 2 + 1 * 5 + 1 * 5 + 10 * 3 = 106 字符。
emmm... 大概就是这么个东西。好了,笔记写完了,继续学习...