1.什么是哈夫曼编码?
1.什么是编码?
编码就是把一些信息比如文字文件、视频文件转成0101的一堆数字存储起来,这些数字就是编码,它们需要满足数字与字符的一一对应关系。当然还必须满足可以由这一堆数字转回到文件信息,这样的编码才是有意义的。
2.问题说明
1.上图编码问题
“我是小张”这句话的确被转成了编码,但是编码“011011”就一定是“我是小张”吗?
其实不难看出,“011011”当然也可以代表“我张我张”。原因很简单,在面对数字1时,我到底是把它当作“是”,还是跟后面的数字结合起来组成其他字符呢?其实0也会有这样的烦恼,只是我们现在编码很少。举个例子,如果“子”的编码是“100",那么我的句子中如果有“子”,其实我是组成“是我我”的。也就是再面对数字0,也会遇到同样的问题。
那么肯定就有聪明的宝子们想到了,让编码等长不就好了吗。
2.等长编码问题
常用汉字是6500个,每个汉字给它一个编码,那么想要实现编码的转换就得13位二进制码,如果用等长编码,当这个汉字的编码只是“10”或“1”,前面就要补十几位的0,这么看来英语还挺好的,手动狗头一下,毕竟只有26个英文字母嘛,最多就是再加个空格符。但是其实也是需要五位二进制码去覆盖所有字母的,难免会有一些字母的编码小,需要补0,这样就浪费了内存空间。
有没有既能无歧义的转回文件,又能使内存消耗最少的方法呢?
聪明的哈夫曼就想到了!
3.解法优化——哈夫曼编码
1.哈夫曼树的形成过程
这里建议看b站up幽蓝伊梦的哈夫曼树详解,这里就不再口述,视频会讲的比较清楚。
2.哈夫曼树的特点说明
图片注明:图(1)与图(2)对比想说明在哈夫曼树时,新节点在左在右都无所谓(即B节点可以在3节点的左边也可以在3节点的右边,A节点同理)
图(3)与图(1)、(2)对比想说明树枝上哪边标1、哪边标0都不重要,这棵树甚至可以是第一层标左边1右边0,第二层标左边0右边1,第三层标左边1右边0的,(如果图1的树按上述说法标注1、0,则编码结果是与图2相同的,感兴趣的同学不妨自己动手一试)
图(4)与图(1)、(2)、(3)对比是想说明对于B、C字符,它们出现的次数是相同的,所以先放谁其实都是无所谓的,对最终的编码长度也并不会造成影响
哈夫曼树是灵活的,哈夫曼树的不同会导致编码结果的不同,但都是对的,都解决了之前提到的编码问题
最终的编码结果的二进制数个数是相同的(长度相同)
3.解决问题1
在哈夫曼编码中,我们不会再遇到见到1个“0”不知道是看作单独的0还是与后边的数结合的问题了。“1”也一样。
我们不妨再用树的形式来看一下之前遇到的问题
显然它与哈夫曼树的区别就是B这个节点处的处理,对于上图,当遇到数字“1”时,我就无法确定它是B还是到达D是路上所经过的1
而对于哈夫曼树,我在同一个位置处把它处理成了非字符节点,确保了第一个分支上的1只能作为通往字符节点的路,从哈夫曼树的结构上,我们也看到了,其实除了最后一层以外,其他的每层只有一个字符节点,也就保证了要么你到达该层的字符节点,要么你就只是作为一个站点路过。
4.问题2的优化
对于内存的优化,哈夫曼编码前需要先计算每个字符出现的次数,从出现次数最少的字符开始从下往上建树,这就保证了出现次数越多的字符,它的所处层级越高,距离根节点也就越近,路径越短,编码越短,这样短的编码赋给出现次数多的字符,长的编码赋给出现次数少的字符,自然总的编码长度就短,所占内存也就少。
2.哈夫曼编码实现文件压缩的原理
我们都知道计算机是利用ASCII码表实现将字符转成0101的二进制数的,而哈夫曼编码则是针对一份具体的文件,生成它自己的一份字符与二进制数相对应的码表,这个码表是针对这一个文件生成的,因此满足上述的内存优化,相比计算机自带的ASCII码表来说,所占内存固然更小,也就实现了文件的压缩。