赫夫曼树(最优二叉树) 赫夫曼编码
首先我们看一下相关的一些概念。
路径长度:从树中一个节点到另外一个节点之间的分支构成两个节点之间的路径,,路径上的分支数目称为路径长度。如图中的数字就为路径长度。
树的路径长度就是从树根到每一个节点的路径的长度总和。上图二叉树的树路径长度为1+1+2+2+2+2+3+3=16。那么根据这样可以得出当节点一样的两棵树,完全二叉树时其树路径长度最小。当为单叉树树时其树的路径长度最大。
带权路径长度:每个叶子的权与根到该叶子的路径长度的乘积之和,记为WPL。
上图二叉树的WPL为:5*3+15*3+40*2+30*2+10*2=220。
赫夫曼树:在具有n个相同的各二叉树中,WPL最小的二叉树。
赫夫曼树的特点:
- 完全二叉树并不一定是赫夫曼树。
- 在赫夫曼树中,权值大的节点离根近。
- 赫夫曼树不唯一,但WPL一定相等。
那么如何构建一棵赫夫曼树???
- 先把有权值的叶子结点按照从小到大的顺序进行排列。A5,E10,B15,D30,C40。
- 取头两个最小权值的节点作为一个新节点N1的两个子节点,相对较小的是左孩子。新节点两个叶子权值的和为15。
- 将N1插入到序列中,此时序列为N1 15,B15,D30,C40。
- 重复步骤2,将N1和B取出来,作为N2的子节点。N2的权值为30。
- N2替换N1与B,此时序列为N2 30,D30,C40。
- 重复步骤2,创建一个新节点N3。
- N3替换N2,D。序列此时为C40,N3 60。
- 重复步骤2,创建一个新节点T(根节点),C为左孩子,此时赫夫曼树创建完成。
此时计算其WPL=205。所以此时这棵树为最优的赫夫曼树。
根据上面的步骤我们可以总结出赫夫曼算法。
- 根据给定的n个权值{w1,w2......wn}构成n棵二叉树的集合F={T1,T2........Tn};其中每棵二叉树只有一个带权的根节点,其左右子树均为空。
- 在F中选取两棵根节点的权值最小的树作为左右子树构造一棵新的二叉树,且新的二叉树的根节点的权值为其左右子树上根节点的权值之和。
- 在F中删除这两个子树,同时将新的二叉树放入F中。
- 重复2和3直到F只有一棵树为止,及赫夫曼树。
赫夫曼编码:为了解决当年远距离通信(电报)的数据传输的最优化问题。
步骤:
- 将字母的频率设定为权值
- 将这些字母按照权值生成赫夫曼树
- 约定左分支表示字符‘0’,右分支表示字符‘1’,则可以用从根结点到叶子结点的路径上的分支字符串作为该叶子结点字符的编码。
这是种不等长编码,将频率高的字母用较短的二进制表示,频率低的则用较长二进制表示,以起到压缩长度的作用。不等长编码必须满足前缀码性质:
前缀码:对每一个字符规定一个0,1串作为其代码,并要求任一字符的代码都不是其他字符代码的前缀。这种编码称为前缀码。
而使用赫夫曼树生成的字母编码必定符合前缀码条件。
我们如果想将ABCDEF传输给别人,那么我们可以用相应的二进制表示:
每个字母传输的频率都是不同的。
那么我们假设六个字母的频率为A27,B8,C15,D15,E30,F5。那么我们可以用赫夫曼树来规划它。
我们将权值的左分支改为0,右分支改为1。那么我们可以得到下表:
我们可以发现数据被压缩了,节省了大约17%的传输成本。
规定赫夫曼树的左分支代表0,右分支代表1,则从根节点到叶子节点所经过的路径分支组成的0和1的序列便为该节点对应字符的编码,这就是赫夫曼编码。