huffman树_哈夫曼树 深入剖析

论树的一个应用,想当然即huffman树,即哈夫曼树

哈夫曼树是一类带权路径最短的树。构造这种树的算法最早由哈夫曼提出,这种树在信息检索中很有用。如用于通讯及数据传送中构造传输效率最高的二进制编码(哈夫曼编码),用于编程中构造平均执行时间最短的最佳判断过程。

基本概念:

节点之间的路径长度:从一个节点到另一个节点之间的分支数目。

树的路径长度:从树的根到树中每一个节点的路径长度之和

如:

3f478d648c6f44397478808dc0e11f2b.png

节点的带权路径长度:从该节点到树根之间的路径长度与节点上权的乘积。

树的带权路径长度:树中所有叶子节点的带权路径长度之和。

如:

d5c9784f1b66bd5082a3f88fbbcc2a3e.png

909fe272bcef820635d405e2ec8fd300.png

即2x5+3x3+7x3+2x1=42

算出来的值最小的二叉树就称作最优二叉树或哈夫曼树。

如果不理解的话可以从网上多找几个例子来看看,有些基础的基本都能很快理解。

然后我们来看看怎么构造哈夫曼树:

哈夫曼算法

① 对于给定的n个权值{W,w2,.. wn}, 构造出具有n棵叉树的森林F={ T, T,, .... T},其中每棵.1叉树T均只有-一个带有权值w;的根结点;

② 在F中选取根结点权值最小的两棵-:叉树作为左、右子树构造一棵新的二叉树,新二叉树根结点的权值为其左、右子树根结点的权值之和;

③ 在F中删除这两棵树,同时将新生成的: 叉树加入F中;

④ 重复②和③,直到F只有一-棵叉树为止,这棵二义树就是所构造的哈夫曼树。

看完是不是看得不太懂?看个实例就知道具体是啥了。

90b1acda9932a4bde209f4a2e6f2dd5f.png

2加3生成5,剩下的就是5,7,5. 然后5加5生成10.剩下的就是7和10,然后就是7和10加起来。然后就有了上面的哈夫曼树了。

刚开始的时候,忽略了2加3生成的5,以为非叶子节点不算在内,后面才发现是算在内的,这也是权值,只不过在算加权路径长度的时候不算进去而已。

看完这个看懂了吗?没事,再来一个

4ebd65237aaf7d4148ed8e98c04c34be.png

相信现在大家应该差不多了吧。

总结一下就是把权值最小的两个数放在最下面先,然后依次把剩下的最小的树慢慢加到这个二叉树上。

然后联系一下前面说的树的带权路径长度最小的就是哈夫曼树,结合现在我们的构造方式,是不是感觉很简单,哈哈。

如果感觉还是不理解的话,可以看百度经验里的链接,里面画的图比较详细。推荐一波:

https://jingyan.baidu.com/article/a501d80c16dfa0ec620f5e70.html

下面是形状和前面的不太一样的情况,但是计算方法都是一样的,我想表示的是要牢牢理解定哈夫曼算法。

783fd2298b21ce59ffde1a25535ca1b5.png

好了,对于哈夫曼树的构造相信大家已经掌握的差不多了。

然后开始学习进一步的知识:

哈夫曼编码,

哈夫曼树应用于通讯及数据传送中对信息的二进制编码。

在计算机数据处理中,霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字符串的平均长度、期望值降低,从而达到无损压缩数据的目的。

例如,在英文中,e的出现机率最高,而z的出现概率则最低。当利用霍夫曼编码对一篇英 文进行压缩时,e极有可能用一个比特来表示,而z则可能花去25个比特(不是26)。用普通的表示方法时,每个英文字母均占用一个字节(byte),即8个比特。二者相比,e使用了一般编码的1/8的长度, z则使用了3倍多。倘若我们能实现对于英文中各个字母出现概率的较准确的估算,就可以大幅度提高无损压缩的比例。

然后用一个具体的图来结合前面的知识来理解这个哈哈夫曼编码:

a97229466bb886cd69e1493037155c86.png

即{E,M,C,A,D}对应的权值为{1,2,3,3,4}

然后就画出上述的哈夫曼树。然后上图还对比了普通编码和哈夫曼编码两种编码长度。可以很直观地发现哈夫曼编码的好处,权值就是出现的概率,有了这个概率后,根据概率进步编码,就能很好地减小长度,提高压缩效果。

下面是另一个例子,可能比较好看一些:

3cfd0f34a82a21b05aa63f923bc42762.png

上面即为普通编码情况。

ea8b90ae4d04c607256eee4d08f72344.png

上面使用哈夫曼编码的情况。

(其实这里我感觉不对啊,b的使用频率相比于其它数值算挺高的了,可是它却放在最底层,占了最长的长度,也就是说会有很多的很长的b串,这明明就违背了它希望的二进制串尽可能短的原则。当时上课没注意,不知道大家有想法木有??)

然后再来看一题:

1e52a6fc5144779b664627a4fe7970b2.png

这题更能充分体现出哈夫曼算法前面的样式都太少了,通过这题大家应该能更好地理解,请大家一定要自己一步一步画出这个哈夫曼树来。

哈夫曼的特点

1.权值越大的叶子节点越靠近根节点,权值越小的叶子节点越远离根节点。

2.只有度为0(叶子节点)和度为2(分支节点)的节点,没有度为1的节点。

在if else中利用哈夫曼树的思想进行优化代码:

比如

if(a==10){

...

}else if(a==20){

....

}else if(a==30){

....

}

这里的前提是不能使用switch的情况下。假设a=30的频率很高,那么当所有的数都经过这个程序,a=30的时候,它就要进行前面的两次判断,而且它的出现概率还很高,所以这重复判断的次数更多,也就是说,这个程序写的效率就很低。这就是利用了统计学的规律来优化我们程序代码的案例。所以我们应该统计概率,然后根据概率来重写这段代码。

感觉讲到这里大家对哈夫曼树的思想已经差不多深入骨髓了吧。

后面来点习题强化理解:

4bc81bed9874c18f8a4d1027c35f09f8.png

这也是一个很不错的题目。

然后我就产生了一个疑问:

41e81758ad8fbd1867b5ccf19e99e802.png

大家看这个2,3,4,5,大家觉得该采用哪种组织方式呢?我的计算应该没错吧?还是说两种组织方式都是可以的呢??(这两个算法应该都是按照规则办事的,算法没问题吧?)

如果两种组织方式都可以,那么我就想起了牛课网的一道题目:

已知一段文本有1382个字符,使用了1382个字节进行存储,这段文本全部是由a、b、c、d、e这5个字符组成,a出现了354次,b出现了483次,c出现了227次,d出现了96次,e出现了232次,对这5个字符使用哈夫曼(Huffman)算法进行编码,则以下哪些说法正确?_迅雷笔试题_牛客网

截图如下:

370dbc5bc45c5fff38de870ee8945cd2.png

官方给出的正确答案是: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表示右子树。这些都只是标准。

然后我咨询了一波老师,说哈夫曼编码不唯一,哈夫曼中,每个字符的编码位数也是不唯一的。这算一个参考答案,敢问客官,你怎么看?

欢迎交流讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值