Huffman 编码压缩算法

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

我们直接来看示例,如果我们需要来压缩下面的字符串:

 “beep boop beer!” 

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

字符 次数
‘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就是字符出现的次数),然后,我们得到下面的数据图表:

同样,我们再把前两个取出来,形成一个Priority为2+2=4的结点,然后再放回Priority Queue中 :

继续我们的算法(我们可以看到,这是一种自底向上的建树的过程):

最终我们会得到下面这样一棵二叉树:

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

最终我们可以得到下面这张编码表:

字符 编码
‘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标准) Download the source files

转载:http://coolshell.cn/articles/7459.html

时间: 2024-10-26 01:58:25

Huffman 编码压缩算法的相关文章

Huffman编码压缩算法之压缩与解压篇

今天的课程设计终于查完了,做了将近一周的Huffman也暂时告一段落了.其间用到了压缩,又开拓了眼界,又认识了一个头文件<bitset>,那我们接下来就小结一下用到的压缩方法. 压缩: while(str.size() >= 8){ string str2(str, 0, 8); //从str中读取前8位 bitset<8> foo(str2); //截取前8位 char bigch = (char)foo.to_ulong(); //将foo转成无符号长整型unsigned

huffman编码压缩算法(转)

参考:http://blog.csdn.net/sunmenggmail/article/details/7598012 笔试时遇到的一道题.

Huffman编码实现压缩解压缩

这是我们的课程中布置的作业,找一些资料将作业完成,顺便将其写到博客,以后看起来也方便. 原理介绍 什么是Huffman压缩 Huffman( 哈夫曼 ) 算法在上世纪五十年代初提出来了,它是一种无损压缩方法,在压缩过程中不会丢失信息熵,而且可以证明 Huffman 算法在无损压缩算法中是最优的. Huffman 原理简单,实现起来也不困难,在现在的主流压缩软件得到了广泛的应用.对应用程序.重要资料等绝对不允许信息丢失的压缩场合, Huffman 算法是非常好的选择. 怎么实现Huffman压缩

Jcompress: 一款基于huffman编码和最小堆的压缩、解压缩小程序

前言 最近基于huffman编码和最小堆排序算法实现了一个压缩.解压缩的小程序.其源代码已经上传到github上面: Jcompress下载地址 .在本人的github上面有一个叫Utility的repository,该分类下面有一个名为Jcompress的目录便是本文所述的压缩.解压缩小程序的源代码.后续会在Utility下面增加其他一些实用的小程序,比如基于socket的文件断点下载小程序等等.如果你读了此文觉得还不错,不防给笔者的github点个star, 哈哈.在正式介绍Jcompres

Huffman编码学习笔记

主要是在学算导,觉得算导译到中国真是中国人民的福音. 一.编码 编码就是选择有意义的01串,令其首尾相接组成文本.我们并非可以随便挑选01串,原因在于它们是首尾相接的,这为我们识别造成了一些困难.比如说我们不能在文本000000中分清字符00与000. 一般我们使用的方式是定长字符:但更好的方式是前缀码,算导中写道"虽然我们这里不会证明,但与任何字符编码相比,前缀码确实可以保证达到最优数据压缩率.",这显然是一个flag,将来一定会有比前缀码更好的编码方式的. 二.Huffman编码便

基于Huffman编码的压缩软件的Python实现

哈夫曼编码是利用贪心算法进行文本压缩的算法,其算法思想是首先统计文件中各字符出现的次数,保存到数组中,然后将各字符按照次数升序排序,挑选次数最小的两个元素进行连结形成子树,子树的次数等于两节点的次数之和,接着把两个元素从数组删除,将子树放入数组,重新排序,重复以上步骤.为了解压,在压缩时首先往文件中填入huffman编码的映射表的长度,该表的序列化字符串,编码字符串分组后最后一组的长度(编码后字符串长度模上分组长度),最后再填充编码后的字符串.本算法中以一个字节,8位作为分组长度,将编码后二进制

基于二叉树和数组实现限制长度的最优Huffman编码

具体介绍详见上篇博客:基于二叉树和双向链表实现限制长度的最优Huffman编码 基于数组和基于链表的实现方式在效率上有明显区别: 编码256个符号,符号权重为1...256,限制长度为16,循环编码1w次,Release模式下.基于链表的耗时为8972ms,基于数组的耗时为1793ms,速度是链表实现方式的5倍. 详细代码例如以下: //Reference:A fast algorithm for optimal length-limited Huffman codes.pdf,http://p

为什么Huffman编码不会发生冲突

关于Huffman编码,这里有一篇漂亮的介绍 http://coolshell.cn/articles/7459.html 似乎介绍Huffman编码的都会有一句“Huffman编码不会发生冲突,即不存在某个编码是另一个编码的前缀”.但是也似乎都没有解释为什么. 细细想明白了之后,觉得似乎又没什么深奥的原理.废话少说,上图. 以上面的图为例子,我们假设这是一个生成Huffman编码的二叉树. 1)所谓的Huffman编码其实就是各个叶节点的路径编码.比如节点H就是010(用左0,右1的规则) 2

霍夫曼编码压缩算法

原址:https://mp.weixin.qq.com/s/PjHuOv8FFHWVn37rKwVTiw 压缩下面的字符串: "beep boop beer!" 首先,我们先计算出每个字符出现的次数,我们得到下面这样一张表 : 然后,我把把这些东西放到Priority Queue中(用出现的次数据当 priority),我们可以看到,Priority Queue 是以Prioirry排序一个数组,如果Priority一样,会使用出现的次序排序:下面是我们得到的Priority Queu