哈夫曼编码详解

前两天发布那个 rsync 算法后,想看看数据压缩的算法,知道一个经典的压缩算法 Huffman 算法。你应该据说过 David Huffman 和他的经典的压缩算法—— Huffman Code,这是一种经过字符出现频率,Priority Queue,和二叉树来进行的一种压缩算法,这种二叉树又叫 Huffman 二叉树 —— 一种带权重的树。可是网上查了一下,中文社区内好像没有把这个算法说得很清楚的文章,尤为是树的构造,而正好看到一篇国外的文章《A Simple Example of Huffman Code on a String》,其中的例子浅显易懂,至关不错,我就转了过来。注意,我没有对此文彻底翻译。算法

  咱们直接来看示例,若是咱们须要来压缩下面的字符串:数组

   “beep boop beer!” oop

  首先,咱们先计算出每一个字符出现的次数,咱们获得下面这样一张表 :编码

字符 次数
‘b’ 3
‘e’ 4
‘p’ 2
‘ ‘ 2
‘o’ 2
‘r’ 1
‘!’ 1

  而后,我把把这些东西放到 Priority Queue 中(用出现的次数据当 priority),咱们能够看到,Priority Queue 是以 Prioirry 排序一个数组,若是 Priority 同样,会使用出现的次序排序:下面是咱们获得的 Priority Queue:翻译

  接下来就是咱们的算法——把这个 Priority Queue 转成二叉树。咱们始终从 queue 的头取两个元素来构造一个二叉树(第一个元素是左结点,第二个是右结点),并把这两个元素的 priority 相加,并放回 Priority 中(再次注意,这里的 Priority 就是字符出现的次数),而后,咱们获得下面的数据图表:3d

  一样,咱们再把前两个取出来,造成一个 Priority 为2+2=4的结点,而后再放回 Priority Queue 中 :code

  继续咱们的算法(咱们能够看到,这是一种自底向上的建树的过程):blog

  最终咱们会获得下面这样一棵二叉树:排序

  此时,咱们把这个树的左支编码为0,右支编码为1,这样咱们就能够遍历这棵树获得字符的编码,好比:‘b’的编码是 00,’p'的编码是 101, ‘r’的编码是 1000。咱们能够看到出现频率越多的会越在上层,编码也越短,出现频率越少的就越在下层,编码也越长ip

  最终咱们能够获得下面这张编码表:

字符 编码
‘b’ 00
‘e’ 11
‘p’ 101
‘ ‘ 011
‘o’ 010
‘r’ 1000
‘!’ 1001

  这里须要注意一点,当咱们 encode 的时候,咱们是按“bit”来 encode,decode 也是经过 bit 来完成,好比,若是咱们有这样的 bitset “1011110111″ 那么其解码后就是 “pepe”。因此,咱们须要经过这个二叉树创建咱们 Huffman 编码和解码的字典表。

  这里须要注意的一点是,咱们的 Huffman 对各个字符的编码是不会冲突的,也就是说,不会存在某一个编码是另外一个编码的前缀,否则的话就会大问题了。由于 encode 后的编码是没有分隔符的。

  因而,对于咱们的原始字符串  beep boop beer!

  其对就能的二进制为 : 0110 0010 0110 0101 0110 0101 0111 0000 0010 0000 0110 0010 0110 1111 0110 1111 0111 0000 0010 0000 0110 0010 0110 0101 0110 0101 0111 0010 0010 0001

  咱们的 Huffman 的编码为: 0011 1110 1011 0001 0010 1010 1100 1111 1000 1001

  从上面的例子中,咱们能够看到被压缩的比例仍是很可观的。

  做者给出了源码你能够看看( C99 标准)

 

还有个特色:哈夫曼树的同一层的节点位置能够互换,可是最终得出来的编码只有惟一前缀的

相关文章
相关标签/搜索