引入
回忆一下,在初学编程时,我们如何通过一个程序判断输入一个分数所属的类别呢?
if (score < 60)
grade = "不及格";
else if (score < 70)
grade = "及格";
else if (score < 80)
grade = "中等";
else if (score < 90)
grade = "良好";
else
grade = "优秀";
上述代码通过如图所示的二叉树结构判断分数类别:
我们可以发现,在之前的表格中,及格与不及格所占的比例总共为20%,而这个程序却对及格与否每次都进行判断,这意味着进行了许多不必要的判断。
相较而言,这颗二叉树则减少了许多不必要的判断。
基本概念
路径:从树中一个节点到另一个节点之间的分支构成的这两个节点之间的路径
路径长度:路径上的分支数目
树的路径长度:从树根到每一个节点的路径长度之和
节点的权:在实际应用中,给树中的节点赋予代表某种含义的数值
节点的带权路径长度:从该节点到树根之间的路径长度与该节点权的乘积
树的带权路径长度(WPL):树中所有叶子节点的带权路径长度之和
这颗二叉树中的权即是各个成绩类别所占的比例。
它的带权路径长度WPL=40*2+30*2+10*2+5*3+15*3=220
这颗简单二叉树的WPL也是如此计算。
定义
带权路径长度WPL最小的二叉树称为哈夫曼树。
先前构造的这颗二叉树虽然比基础二叉树的带权路径长度更短,但并不是哈夫曼树。
哈夫曼树有自己的构造方法。
构造哈夫曼树
1.先把有权值的叶子节点按照从小到大的顺序排列成一个有序序列
2.取两个最小权值的节点作为一个新节点N1的子节点(注意左子树权小,右子树权大)
3.将节点N1替换刚刚取出的两个节点,并加入有序序列中再次排序
4.重复步骤2,将N1和“及格”作为一个新节点N2的子节点
不断重复上述步骤,直到得到一颗二叉树,这就是哈夫曼树。
它的WPL=40*1+30*2+15*3+5*4+10*4=205
哈夫曼编码
例:
有一段字符内容“BADCADFEED”通过网络传输:
假设六个字母的使用频率为
画出它的哈夫曼树:
然后将所有的链接左子树的路径标上0,所有链接右子树的路径标上1
这样就得到了字母的哈夫曼编码
原编码的二进制串为:001 000 011 010 000 011 101 100 100 011
哈夫曼编码二进制串: 1001 01 00 101 01 00 1000 11 11 00
编码长度得到肉眼可见的缩短,这种缩短在处理成千上万的信息时更能体现出优势。
补充知识
如果哈夫曼树有N个叶子节点,则它总共必然有2N-1个节点。