哈夫曼树

原创 2007年10月08日 15:23:00
哈夫曼树
在一般的数据结构的书中,树的那章后面,著者一般都会介绍一下哈夫曼(HUFFMAN)树和哈夫曼编码。哈夫曼编码是哈夫曼树的一个应用。哈夫曼编码应用广泛,如JPEG中就应用了哈夫曼编码。

首先介绍什么是哈夫曼树。哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的带权路径长度记为WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。可以证明哈夫曼树的WPL是最小的。

哈夫曼在上世纪五十年代初就提出这种编码时,根据字符出现的概率来构造平均长度最短的编码。它是一种变长的编码。在编码中,若各码字长度严格按照码字所对应符号出现概率的大小的逆序排列,则编码的平均长度是最小的。(注:码字即为符号经哈夫曼编码后得到的编码,其长度是因符号出现的概率而不同,所以说哈夫曼编码是变长的编码。)

然而怎样构造一棵哈夫曼树呢?最具有一般规律的构造方法就是哈夫曼算法。一般的数据结构的书中都可以找到其描述:

一、对给定的n个权值{W1,W2,W3,...,Wi,...,Wn}构成n棵二叉树的初始集合F={T1,T2,T3,...,Ti,...,Tn},其中每棵二叉树Ti中只有一个权值为Wi的根结点,它的左右子树均为空。(为方便在计算机上实现算法,一般还要求以Ti的权值Wi的升序排列。)

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

三、从F中删除这两棵树,并把这棵新的二叉树同样以升序排列加入到集合F中。

四、重复二和三两步,直到集合F中只有一棵二叉树为止。

用C语言实现上述算法,可用静态的二叉树或动态的二叉树。若用动态的二叉树可用以下数据结构: struct tree{

float weight; /*权值*/

union{

char leaf; /*叶结点信息字符*/

struct tree *left; /*树的左结点*/

};

struct tree *right; /*树的右结点*/

};

struct forest{ /*F集合,以链表形式表示*/

struct tree *ti; /* F中的树*/

struct forest *next; /* 下一个结点*/

};

例:若字母A,B,Z,C出现的概率为:0.75,0.54,0.28,0.43;则相应的权值为:75,54,28,43。

构造好哈夫曼树后,就可根据哈夫曼树进行编码。例如:上面的字符根据其出现的概率作为权值构造一棵哈夫曼树后,经哈夫曼编码得到的对应的码值。只要使用同一棵哈夫曼树,就可把编码还原成原来那组字符。显然哈夫曼编码是前缀编码,即任一个字符的编码都不是另一个字符的编码的前缀,否则,编码就不能进行翻译。例如:a,b,c,d的编码为:0,10,101,11,对于编码串:1010就可翻译为bb或ca,因为b的编码是c的编码的前缀。刚才进行哈夫曼编码的规则是从根结点到叶结点(包含原信息)的路径,向左孩子前进编码为0,向右孩子前进编码为1,当然你也可以反过来规定。

这种编码方法是静态的哈夫曼编码,它对需要编码的数据进行两遍扫描:第一遍统计原数据中各字符出现的频率,利用得到的频率值创建哈夫曼树,并必须把树的信息保存起来,即把字符0-255(2^8=256)的频率值以2-4BYTES的长度顺序存储起来,(用4Bytes的长度存储频率值,频率值的表示范围为0--2^32-1,这已足够表示大文件中字符出现的频率了)以便解压时创建同样的哈夫曼树进行解压;第二遍则根据第一遍扫描得到的哈夫曼树进行编码,并把编码后得到的码字存储起来。 静态哈夫曼编码方法有一些缺点:一、对于过短的文件进行编码的意义不大,因为光以4BYTES的长度存储哈夫曼树的信息就需1024Bytes的存储空间;二、进行哈夫曼编码,存储编码信息时,若用与通讯网络,就会引起较大的延时;三、对较大的文件进行编码时,频繁的磁盘读写访问会降低数据编码的速度。

因此,后来有人提出了一种动态的哈夫曼编码方法。动态哈夫曼编码使用一棵动态变化的哈夫曼树,对第t+1个字符的编码是根据原始数据中前t个字符得到的哈夫曼树来进行的,编码和解码使用相同的初始哈夫曼树,每处理完一个字符,编码和解码使用相同的方法修改哈夫曼树,所以没有必要为解码而保存哈夫曼树的信息。编码和解码一个字符所需的时间与该字符的编码长度成正比,所以动态哈夫曼编码可实时进行。动态哈夫曼编码比静态哈夫曼编码复杂的多,有兴趣的读者可参考有关数据结构与算法的书籍。

前面提到的JPEG中用到了哈夫曼编码,并不是说JPEG就只用哈夫曼编码就可以了,而是一幅图片经过多个步骤后得到它的一列数值,对这些数值进行哈夫曼编码,以便存储或传输。哈夫曼编码方法比较易懂,大家可以根据它的编码方法,自己编写哈夫曼编码和解码的程序。
 

数据结构基础系列(8):查找

数据结构课程是计算机类专业的专业基础课程,在IT人才培养中,起着重要的作用。课程按照大学计算机类专业课程大纲的要求,安排教学内容,满足需要系统学习数据结构的人。系列课程包含11个部分,本课为第8部分查找,介绍查找的基本概念,重点是线性表上顺序查找、二分查找和分块查找,二叉排序树、AVL树和B-树的各种树表,以及哈希表查找。
  • 2015年11月16日 15:26

哈夫曼树的创建和编码

哈夫曼树的创建和编码                    1.哈夫曼树又称最优二叉树,是一类带权路径长度最短的树。        对于最优二叉树,权值越大的结点越接近树的根结点,权值越小的结点越远...
  • wp1603710463
  • wp1603710463
  • 2016-03-19 21:30:16
  • 12991

哈夫曼树学习小记

B组又现我不会的神奇东西了……定义:现在有n个元素,每个元素有一个值。 你需要把这n个元素放在一棵二叉树的叶子节点上,规定每个元素的代价为它所在叶子节点的深度乘上它的值,哈夫曼树就是使总代价最小的这...
  • Cold_Chair
  • Cold_Chair
  • 2017-08-24 15:37:22
  • 342

树结构(四) - 哈夫曼树的原理与实现

一、哈夫曼树的介绍 Huffman Tree,中文名是哈夫曼树或霍夫曼树,它是最优二叉树。 定义:给定n个权值作为n个叶子结点,构造一棵二叉树,若树的带权路径长度达到最小,则这棵树被称为哈夫曼树。 这...
  • leicool_518
  • leicool_518
  • 2015-01-13 13:24:00
  • 2163

哈夫曼树例子

五个字符:a,b,c,d,e,它们出现的的频率为8,14,10,4,18构造相应的哈夫曼树,求出每个字符的哈夫曼编码: 哈夫曼树: 54 / ...
  • u013063153
  • u013063153
  • 2015-09-03 20:38:10
  • 1436

哈夫曼树简介及实现

初识哈夫曼树是一种带权路径长度最短的二叉树,所以它又称为最优二叉树.主要用途利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码,例如设计电文总长最短的二进制前缀编码,就是以n个字符出现的频率作为权构...
  • leo_wc
  • leo_wc
  • 2017-05-27 17:58:17
  • 337

哈夫曼树的课程设计

摘  要在计算机信息处理中,“哈夫曼编码”是一种一致性编码法(又称"熵编码法"),用于数据的无损耗压缩。我们会发现一些数据经常出现的频率高,有些出现的频率低。我们利用哈夫曼算法建立一棵哈夫曼树(最优二...
  • pandana
  • pandana
  • 2009-12-27 09:59:00
  • 2925

哈夫曼树的代码实现

定义 哈夫曼树,又称最优树,是一类带权路径长度最短的树。 树的带权路径长度,是树中所有叶子 节点的带权路径长度之和。通常记做WPL=W1*L1+W2*L2+...+Wn*Ln。 例如: 节...
  • cqnuztq
  • cqnuztq
  • 2013-05-13 10:20:28
  • 20778

哈夫曼树-贪心算法的应用实例

/* *哈夫曼编码-链式结构 * *功能实现: * 源文件字符权值确认操作 * 哈夫曼树的建立操作 * 字符字典的建立操作 * 源文件转码操作操作 * 二进制文件译码操作 * 文件输出操作...
  • a915650754
  • a915650754
  • 2014-12-07 23:11:35
  • 1504

数据结构之---C语言实现哈夫曼树和编码

数据结构之---C语言实现哈夫曼树和编码
  • u012965373
  • u012965373
  • 2015-07-03 00:03:01
  • 6350
收藏助手
不良信息举报
您举报文章:哈夫曼树
举报原因:
原因补充:

(最多只允许输入30个字)