找回密码
 立即注册
查看: 174|回复: 0

哈夫曼编码(Huffman Coding)多图详细解析

[复制链接]
发表于 2023-2-18 21:34 | 显示全部楼层 |阅读模式
哈夫曼编码

哈夫曼编码,又称为霍夫曼编码,它是现代压缩算法的基础。假如我们需要将字符串ABBBCCCCCCCCDDDDDDEE通过二进制编码进行传输,那应该怎么将字符转换为二进制码?
方法一:转换为ASCII码

直接将字母转换为对应的ASCII码数字,再将ASCII码转换为对应的二进制码
字母ASCII码二进制码
A65100 0001
B66100 0010
C67100 0011
D68100 0100
E69100 0101
显然这样的方式使得二进制码变得很长。
方法二:事先约定5个字母对应的二进制码

字母ASCII码二进制码
A00
B11
C210
D311
E4100
此时ABBBCC的二进制编码为:01111010,但是我们并不能对其进行解码,这是因为:对于二进制码的第一位0,我们可以立刻判断出是字母A,但对于之后的1111,可以解码为BBBB,也可以解码为DD,也可以…,在此无法进行解码的原因是:存在某个字母的编码是其他字母的前缀,甚至有字母的编码是由其他字母的编码组成。
字母ASCII码二进制码
A0000
B1001
C2010
D3011
E4100
对此我们可以约定每三个二进制位代表一个字母,那么就不存在编码的前缀关系了,解码的问题也可以顺利解决。原字符串的二进制编码为:000001001001010010010010010010010010011011011011011011100100,可以预见的是,方法二的编码一定比方法一短了很多。
方法三:哈夫曼编码

如果使用哈夫曼编码,该字符串可以压缩至41个二进制位,约为原来长度的68.3%。
在构建哈夫曼编码时,我们首先要统计字符串中每个字母的出现频率(这是为了将短的二进制码分配给频率高的字母,以达到缩短二进制码长度的目的),在这里直接通过出现次数进行比较。
ABCDE
13862
利用这些权值,我们就可以构建一棵哈夫曼树(又称为霍夫曼树、最优二叉树)。
构建哈夫曼树

假设我们有n个不同的字母,对应n个权值。
    构建n棵只有根节点的二叉树构成森林,根节点的值为n个字母与权值

2. 在森林里选出两棵根节点值最小的树进行合并,合并方式为生成一棵新树,根节点值为两棵树根节点值权值之和,且让两棵树作为新树的左右子树。将两棵树从森林删除,新树加入森林。


3. 重复 2 的操作,直到森林只剩一棵树为止,该树即为哈夫曼树






构建哈夫曼编码

此时哈夫曼树构建完成了,下面我们要对各个字母进行编码,编码原则是,从哈夫曼树的根节点开始,进入左子树则编码号加0,进入右子树则编码号加1,就可以得到对应字母的二进制编码。

各个字母的编码如下:
ABCDE
11101100101111
此时字符串:ABBBCCCCCCCCDDDDDDEE的哈夫曼编码是1110110110110000000001010101010101111,显然比方法二中的编码短了。
总结

    那么为什么通过哈夫曼编码后得到的二进制码不会有前缀的问题呢?
这是因为在哈夫曼树中,每个字母对应的节点都是叶子节点,而他们对应的二进制码是由根节点到各自节点的路径所决定的,正因为是叶子节点,每个节点的路径不可能和其他节点有前缀的关系。
    为什么通过哈夫曼编码获得的二进制码短呢?
因为哈夫曼树是带权路径长度最短的树,权值较大的节点离根节点较近。而带权路径长度是指:树中所有的叶子节点的权值乘上其到根节点的路径长度,这与最终的哈夫曼编码总长度成正比关系的。对于第二种方式的编码,我们也可以按0左1右的规则构成一棵二叉树,但显然他没有按权值高的节点离根节点近的原则去构建二叉树,带权路径长度更长,二进制码也更长。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-24 05:20 , Processed in 0.099574 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表