论树的一个应用,想当然即huffman树,即哈夫曼树
哈夫曼树是一类带权路径最短的树。构造这种树的算法最早由哈夫曼提出,这种树在信息检索中很有用。如用于通讯及数据传送中构造传输效率最高的二进制编码(哈夫曼编码),用于编程中构造平均执行时间最短的最佳判断过程。
基本概念:
节点之间的路径长度:从一个节点到另一个节点之间的分支数目。
树的路径长度:从树的根到树中每一个节点的路径长度之和
如:
节点的带权路径长度:从该节点到树根之间的路径长度与节点上权的乘积。
树的带权路径长度:树中所有叶子节点的带权路径长度之和。
如:
即2x5+3x3+7x3+2x1=42
算出来的值最小的二叉树就称作最优二叉树或哈夫曼树。
如果不理解的话可以从网上多找几个例子来看看,有些基础的基本都能很快理解。
然后我们来看看怎么构造哈夫曼树:
哈夫曼算法
① 对于给定的n个权值{W,w2,.. wn}, 构造出具有n棵叉树的森林F={ T, T,, .... T},其中每棵.1叉树T均只有-一个带有权值w;的根结点;
② 在F中选取根结点权值最小的两棵-:叉树作为左、右子树构造一棵新的二叉树,新二叉树根结点的权值为其左、右子树根结点的权值之和;
③ 在F中删除这两棵树,同时将新生成的: 叉树加入F中;
④ 重复②和③,直到F只有一-棵叉树为止,这棵二义树就是所构造的哈夫曼树。
看完是不是看得不太懂?看个实例就知道具体是啥了。
2加3生成5,剩下的就是5,7,5. 然后5加5生成10.剩下的就是7和10,然后就是7和10加起来。然后就有了上面的哈夫曼树了。
刚开始的时候,忽略了2加3生成的5,以为非叶子节点不算在内,后面才发现是算在内的,这也是权值,只不过在算加权路径长度的时候不算进去而已。
看完这个看懂了吗?没事,再来一个
相信现在大家应该差不多了吧。
总结一下就是把权值最小的两个数放在最下面先,然后依次把剩下的最小的树慢慢加到这个二叉树上。
然后联系一下前面说的树的带权路径长度最小的就是哈夫曼树,结合现在我们的构造方式,是不是感觉很简单,哈哈。
如果感觉还是不理解的话,可以看百度经验里的链接,里面画的图比较详细。推荐一波:
https://jingyan.baidu.com/article/a501d80c16dfa0ec620f5e70.html
下面是形状和前面的不太一样的情况,但是计算方法都是一样的,我想表示的是要牢牢理解定哈夫曼算法。
好了,对于哈夫曼树的构造相信大家已经掌握的差不多了。
然后开始学习进一步的知识:
哈夫曼编码,
哈夫曼树应用于通讯及数据传送中对信息的二进制编码。
在计算机数据处理中,霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字符串的平均长度、期望值降低,从而达到无损压缩数据的目的。
例如,在英文中,e的出现机率最高,而z的出现概率则最低。当利用霍夫曼编码对一篇英 文进行压缩时,e极有可能用一个比特来表示,而z则可能花去25个比特(不是26)。用普通的表示方法时,每个英文字母均占用一个字节(byte),即8个比特。二者相比,e使用了一般编码的1/8的长度, z则使用了3倍多。倘若我们能实现对于英文中各个字母出现概率的较准确的估算,就可以大幅度提高无损压缩的比例。
然后用一个具体的图来结合前面的知识来理解这个哈哈夫曼编码:
即{E,M,C,A,D}对应的权值为{1,2,3,3,4}
然后就画出上述的哈夫曼树。然后上图还对比了普通编码和哈夫曼编码两种编码长度。可以很直观地发现哈夫曼编码的好处,权值就是出现的概率,有了这个概率后,根据概率进步编码,就能很好地减小长度,提高压缩效果。
下面是另一个例子,可能比较好看一些:
上面即为普通编码情况。
上面使用哈夫曼编码的情况。
(其实这里我感觉不对啊,b的使用频率相比于其它数值算挺高的了,可是它却放在最底层,占了最长的长度,也就是说会有很多的很长的b串,这明明就违背了它希望的二进制串尽可能短的原则。当时上课没注意,不知道大家有想法木有??)
然后再来看一题:
这题更能充分体现出哈夫曼算法前面的样式都太少了,通过这题大家应该能更好地理解,请大家一定要自己一步一步画出这个哈夫曼树来。
哈夫曼的特点:
1.权值越大的叶子节点越靠近根节点,权值越小的叶子节点越远离根节点。
2.只有度为0(叶子节点)和度为2(分支节点)的节点,没有度为1的节点。
在if else中利用哈夫曼树的思想进行优化代码:
比如
if(a==10){
...
}else if(a==20){
....
}else if(a==30){
....
}
这里的前提是不能使用switch的情况下。假设a=30的频率很高,那么当所有的数都经过这个程序,a=30的时候,它就要进行前面的两次判断,而且它的出现概率还很高,所以这重复判断的次数更多,也就是说,这个程序写的效率就很低。这就是利用了统计学的规律来优化我们程序代码的案例。所以我们应该统计概率,然后根据概率来重写这段代码。
感觉讲到这里大家对哈夫曼树的思想已经差不多深入骨髓了吧。
后面来点习题强化理解:
这也是一个很不错的题目。
然后我就产生了一个疑问:
大家看这个2,3,4,5,大家觉得该采用哪种组织方式呢?我的计算应该没错吧?还是说两种组织方式都是可以的呢??(这两个算法应该都是按照规则办事的,算法没问题吧?)
如果两种组织方式都可以,那么我就想起了牛课网的一道题目:
已知一段文本有1382个字符,使用了1382个字节进行存储,这段文本全部是由a、b、c、d、e这5个字符组成,a出现了354次,b出现了483次,c出现了227次,d出现了96次,e出现了232次,对这5个字符使用哈夫曼(Huffman)算法进行编码,则以下哪些说法正确?_迅雷笔试题_牛客网
截图如下:
官方给出的正确答案是:A C D
然后下面也有人给出解释:
链接:https://www.nowcoder.com/questionTerminal/0ad28ca1b2d44e0fbaddc0d076d607a9
来源:牛客网
A正确,Huffman树就是求最优解。可以有多套方案,但最终每套方案生成的编码长度都相同且都是最优解。
B错误,我们可以将左子树定为1右子树定为0也可以反之,不同的方案获得的编码值是不同的,但每个字符的编码长度是固定的。
C正确,不同的方案影响的只是通向节点的路径为0还是1,而不会影响Huffman树的层次结构
D正确,生成了Huffman树之后,我们就能看到,出现频率越高的节点越靠近根,深度越小即编码值尾数越短;出现频率越低的节点越远离根,深度越大即编码位数越长。
这里大家可以参阅着学习。大家可以前往链接的讨论区看看。
我的疑问就是C还有B的选项及其解释的正确性。每个字符编码的位(bit)数是确定的。然后反手回去看我上面提出的疑问,这里面不就是都是最优解,但是字符编码的位数应该不确定吧??或者说这个结论只是针对本题而言的吗?
不过解释B中的,将左子树定为0或1都是可以的,所以编码值不是唯一的,这个我倒是很赞同的,毕竟没有强行说限制一定要0表示左子树,1表示右子树。这些都只是标准。
然后我咨询了一波老师,说哈夫曼编码不唯一,哈夫曼中,每个字符的编码位数也是不唯一的。这算一个参考答案,敢问客官,你怎么看?
欢迎交流讨论。