赫夫曼树及其编码
最优二叉树(哈夫曼树)的构建及编码

最优⼆叉树(哈夫曼树)的构建及编码参考:数据结构教程(第五版)李春葆主编⼀,概述1,概念 结点的带权路径长度: 从根节点到该结点之间的路径长度与该结点上权的乘积。
树的带权路径长度: 树中所有叶结点的带权路径长度之和。
2,哈夫曼树(Huffman Tree) 给定 n 个权值作为 n 个叶⼦结点,构造⼀棵⼆叉树,若该树的带权路径长度达到最⼩,则称这样的⼆叉树为最优⼆叉树,也称为哈夫曼树。
哈夫曼树是带权路径长度最短的树,权值较⼤的结点离根较近。
⼆,哈夫曼树的构建1,思考 要实现哈夫曼树⾸先有个问题摆在眼前,那就是哈夫曼树⽤什么数据结构表⽰? ⾸先,我们想到的肯定数组了,因为数组是最简单和⽅便的。
⽤数组表⽰⼆叉树有两种⽅法: 第⼀种适⽤于所有的树。
即利⽤树的每个结点最多只有⼀个⽗节点这种特性,⽤ p[ i ] 表⽰ i 结点的根节点,进⽽表⽰树的⽅法。
但这种⽅法是有缺陷的,权重的值需要另设⼀个数组表⽰;每次找⼦节点都要遍历⼀遍数组,⼗分浪费时间。
第⼆种只适⽤于⼆叉树。
即利⽤⼆叉树每个结点最多只有两个⼦节点的特点。
从下标 0 开始表⽰根节点,编号为 i 结点即为 2 * i + 1 和 2 * i + 2,⽗节点为 ( i - 1) / 2,没有⽤到的空间⽤ -1 表⽰。
但这种⽅法也有问题,即哈夫曼树是从叶结点⾃下往上构建的,⼀开始树叶的位置会因为⽆法确定⾃⾝的深度⽽⽆法确定,从⽽⽆法构造。
既然如此,只能⽤⽐较⿇烦的结构体数组表⽰⼆叉树了。
typedef struct HTNode // 哈夫曼树结点{double w; // 权重int p, lc, rc;}htn;2,算法思想 感觉⽐较偏向于贪⼼,权重最⼩的叶⼦节点要离根节点越远,⼜因为我们是从叶⼦结点开始构造最优树的,所以肯定是从最远的结点开始构造,即权重最⼩的结点开始构造。
所以先选择权重最⼩的两个结点,构造⼀棵⼩⼆叉树。
然后那两个最⼩权值的结点因为已经构造完了,不会在⽤了,就不去考虑它了,将新⽣成的根节点作为新的叶⼦节加⼊剩下的叶⼦节点,⼜因为该根节点要能代表整个以它为根节点的⼆叉树的权重,所以其权值要为其所有⼦节点的权重之和。
5.2哈夫曼树与哈夫曼编码

T->Left = DeleteMin(H);
/*从最小堆中删除一个结点,作为新T的左子结点*/
T->Right = DeleteMin(H);
/*从最小堆中删除一个结点,作为新T的右子结点*/
T->Weight = T->Left->Weight+T->Right->Weight;
/*计算新权值*/
可以无二义地解码
二叉树用于编码
用二叉树进行编码: (1)左右分支:0、1 (2)字符只在叶结点上
四个字符的频率: a:4, u:1, x:2, z:1
1
0
1
0 01
axuz
01
01 01 auxz
Cost ( aaaxuaxz 00010110010111) = 14 + 31 + 22 + 31 = 14
分数段 0-59 60-69 70-79 80-89 90-100 比例 0.05 0.15 0.40 0.30 0.10
修改判定树:
yes score<80 no
yes score<70 no
yes score<90 no
yes score<60 no
grade=3
grade=4 grade=5
【分析】 (1)用等长ASCII编码:58 ×8 = 464位; (2)用等长3位编码:58 ×3 = 174位; (3)不等长编码:出现频率高的字符用的编码短些,出现频率低 的字符则可以编码长些?
怎么进行不等长编码? 如何避免二义性?
前缀码prefix code:任何字符的编码都不是另一字符编码的前缀
判定树:
c语言哈夫曼树的构造及编码

c语言哈夫曼树的构造及编码一、哈夫曼树概述哈夫曼树是一种特殊的二叉树,它的构建基于贪心算法。
它的主要应用是在数据压缩和编码中,可以将频率高的字符用较短的编码表示,从而减小数据存储和传输时所需的空间和时间。
二、哈夫曼树的构造1. 哈夫曼树的定义哈夫曼树是一棵带权路径长度最短的二叉树。
带权路径长度是指所有叶子节点到根节点之间路径长度与其权值乘积之和。
2. 构造步骤(1) 将待编码字符按照出现频率从小到大排序。
(2) 取出两个权值最小的节点作为左右子节点,构建一棵新的二叉树。
(3) 将新构建的二叉树加入到原来排序后队列中。
(4) 重复上述步骤,直到队列只剩下一个节点,该节点即为哈夫曼树的根节点。
3. C语言代码实现以下代码实现了一个简单版哈夫曼树构造函数:```ctypedef struct TreeNode {int weight; // 权重值struct TreeNode *leftChild; // 左子节点指针struct TreeNode *rightChild; // 右子节点指针} TreeNode;// 构造哈夫曼树函数TreeNode* createHuffmanTree(int* weights, int n) {// 根据权值数组构建节点队列,每个节点都是一棵单独的二叉树TreeNode** nodes = (TreeNode**)malloc(sizeof(TreeNode*) * n);for (int i = 0; i < n; i++) {nodes[i] = (TreeNode*)malloc(sizeof(TreeNode));nodes[i]->weight = weights[i];nodes[i]->leftChild = NULL;nodes[i]->rightChild = NULL;}// 构建哈夫曼树while (n > 1) {int minIndex1 = -1, minIndex2 = -1;for (int i = 0; i < n; i++) {if (nodes[i] != NULL) {if (minIndex1 == -1 || nodes[i]->weight < nodes[minIndex1]->weight) {minIndex2 = minIndex1;minIndex1 = i;} else if (minIndex2 == -1 || nodes[i]->weight < nodes[minIndex2]->weight) {minIndex2 = i;}}}TreeNode* newNode =(TreeNode*)malloc(sizeof(TreeNode));newNode->weight = nodes[minIndex1]->weight + nodes[minIndex2]->weight;newNode->leftChild = nodes[minIndex1];newNode->rightChild = nodes[minIndex2];// 将新构建的二叉树加入到原来排序后队列中nodes[minIndex1] = newNode;nodes[minIndex2] = NULL;n--;}return nodes[minIndex1];}```三、哈夫曼编码1. 哈夫曼编码的定义哈夫曼编码是一种前缀编码方式,它将每个字符的编码表示为二进制串。
哈夫曼树及哈夫曼编码的算法实现c语言

哈夫曼树及哈夫曼编码的算法实现c语言1.引言1.1 概述哈夫曼树及哈夫曼编码是数据压缩和编码中常用的重要算法。
哈夫曼树由大卫·哈夫曼于1952年提出,用于根据字符出现的频率构建一种最优的前缀编码方式。
而哈夫曼编码则是根据哈夫曼树构建的编码表将字符进行编码的过程。
在现代通信和计算机领域,数据传输和存储中往往需要大量的空间。
为了有效利用有限的资源,减少数据的存储和传输成本,数据压缩成为一个重要的技术。
而哈夫曼树及哈夫曼编码正是数据压缩中常用的技术之一。
哈夫曼树的概念及原理是基于字符的频率和概率进行构建的。
在哈夫曼树中,字符出现频率越高的节点越接近根节点,出现频率越低的节点离根节点越远。
这种构建方式保证了哈夫曼树的最优性,即最小化编码的总长度。
哈夫曼编码的算法实现是根据哈夫曼树构建的编码表进行的。
编码表中,每个字符都与一段二进制编码相对应。
在进行数据压缩和解压缩时,通过查表的方式将字符转化为相应的二进制编码,或将二进制编码解析为原始字符。
本文旨在介绍哈夫曼树及哈夫曼编码的概念和原理,并通过C语言实现算法。
通过深入理解哈夫曼树及哈夫曼编码的实现过程,可以更好地理解数据压缩和编码的原理,为后续的研究和应用提供基础。
接下来,我们将首先介绍哈夫曼树的概念和原理,然后详细讲解哈夫曼编码的算法实现。
最后,我们将总结哈夫曼树及哈夫曼编码的重要性,并提出对哈夫曼树和哈夫曼编码进一步研究的方向。
让我们一起深入探索哈夫曼树及哈夫曼编码的奥秘吧!1.2 文章结构文章结构部分的内容可以包括以下内容:文章结构部分主要介绍了本文的组织结构和各个章节的内容概述,以帮助读者更好地理解全文的逻辑结构和内容安排。
首先,本文包括引言、正文和结论三个部分。
引言部分主要对哈夫曼树及哈夫曼编码的算法实现进行了概述,包括相关的概念、原理和目的。
正文部分则深入介绍了哈夫曼树的概念和原理,以及哈夫曼编码的算法实现。
最后,结论部分对本文的主要内容进行了总结,并提出了对哈夫曼树和哈夫曼编码的进一步研究方向。
哈夫曼(huffman)树和哈夫曼编码

哈夫曼(huffman)树和哈夫曼编码讨论QQ群:待定哈夫曼树哈夫曼树也叫最优二叉树(哈夫曼树)问题:什么是哈夫曼树?例:将学生的百分制成绩转换为五分制成绩:≥90 分: A,80~89分: B,70~79分: C,60~69分: D,<60分: E。
if (a < 60){b = 'E';}else if (a < 70) {b = ‘D’;}else if (a<80) {b = ‘C’;}else if (a<90){b = ‘B’;}else {b = ‘A’;}判别树:用于描述分类过程的二叉树。
如果每次输入量都很大,那么应该考虑程序运行的时间如果学生的总成绩数据有10000条,则5%的数据需1 次比较,15%的数据需 2 次比较,40%的数据需 3 次比较,40%的数据需 4 次比较,因此 10000 个数据比较的次数为: 10000 (5%+2×15%+3×40%+4×40%)=31500次此种形状的二叉树,需要的比较次数是:10000 (3×20%+2×80%)=22000次,显然:两种判别树的效率是不一样的。
问题:能不能找到一种效率最高的判别树呢?那就是哈夫曼树回忆树的基本概念和术语路径:若树中存在一个结点序列k1,k2,…,kj,使得ki是ki+1的双亲,则称该结点序列是从k1到kj的一条路径。
路径长度:等于路径上的结点数减1。
结点的权:在许多应用中,常常将树中的结点赋予一个有意义的数,称为该结点的权。
结点的带权路径长度:是指该结点到树根之间的路径长度与该结点上权的乘积。
树的带权路径长度:树中所有叶子结点的带权路径长度之和,通常记作:其中,n表示叶子结点的数目,wi和li分别表示叶子结点ki的权值和树根结点到叶子结点ki之间的路径长度。
赫夫曼树(哈夫曼树,huffman树)定义:在权为w1,w2,…,wn的n个叶子结点的所有二叉树中,带权路径长度WPL最小的二叉树称为赫夫曼树或最优二叉树。
数据结构(二十七)Huffman树和Huffman编码

数据结构(⼆⼗七)Huffman树和Huffman编码 Huffman树是⼀种在编码技术⽅⾯得到⼴泛应⽤的⼆叉树,它也是⼀种最优⼆叉树。
⼀、霍夫曼树的基本概念 1.结点的路径和结点的路径长度:结点间的路径是指从⼀个结点到另⼀个结点所经历的结点和分⽀序列。
结点的路径长度是指从根结点到该结点间的路径上的分⽀数⽬。
2.结点的权和结点的带权路径长度:结点的权是指结点被赋予⼀个具有某种实际意义的数值。
结点的带权路径长度是该结点的路径长度与结点的权值的乘积。
3.树的长度和树的带权路径长度:树的长度就是从根结点到每⼀结点的路径长度之和。
树的带权路径长度就是所有叶结点的带权路径长度之和。
4.最优⼆叉树:带权路径长度WPL最⼩的⼆叉树称为霍夫曼树(Huffman Tree)或最优⼆叉树。
⼆叉树a的WPL = 5 x 1 + 15 x 2 + 40 x 3 + 30 x 4 + 10 x 5 = 315 ⼆叉树b的WPL = 5 x 3 + 15 x 3 + 40 x 2 + 30 x 2 + 10 x 2 = 220 ⼆、霍夫曼树的构造⽅法由给定的n个权值{w1,w2,... ,wn}构成由n棵⼆叉树所构成的森林F={T1,T2,...,Tn},其中每棵⼆叉树只有⼀个根结点,并且根结点的权值对应于w1,w2,...,wn在F中选取根结点的权值最⼩的两棵树,分别把它们作为左⼦树和右⼦树去构造⼀棵新的⼆叉树,新的⼆叉树的各结点的权值为左、右⼦树的权值之和在F中删除上⼀步中选中的两棵树,并把新产⽣的⼆叉树加⼊到F中重复第2步和第3步,直到F只含⼀棵树为⽌,这棵树就是霍夫曼树。
三、霍夫曼编码 霍夫曼树更⼤的⽬的是解决了当年远距离通信(电报)的数据传输的最优化问题。
霍夫曼编码的定义:设需要编码的字符集为(d1,d2,...,dn)各个字符在电⽂中出现的次数或者频率集合为{w1,w2,...,wn},以d1,d2,...,dn为叶⼦结点,w1,w2,...,wn作为相应叶⼦结点的权值来构造⼀棵霍夫曼树。
数据结构c+python代码6:哈夫曼树构造及编码

数据结构c+python代码6:哈夫曼树构造及编码⾸先介绍⼀下什么是哈夫曼树?给定N个权值作为N个叶⼦结点,构造⼀棵⼆叉树,若该树的带权路径长度达到最⼩,称这样的⼆叉树为最优⼆叉树,也称为哈夫曼树(Huffman Tree)。
哈夫曼树是带权路径长度最短的树,权值较⼤的结点离根较近。
哈夫曼树⼜称为最优树.1、路径和路径长度在⼀棵树中,从⼀个结点往下可以达到的孩⼦或孙⼦结点之间的通路,称为路径。
通路中分⽀的数⽬称为路径长度。
若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
2、结点的权及带权路径长度哈夫曼树哈夫曼树(3张)若将树中结点赋给⼀个有着某种含义的数值,则这个数值称为该结点的权。
结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
3、树的带权路径长度树的带权路径长度规定为所有叶⼦结点的带权路径长度之和,记为WPL。
哈夫曼树的构造假设有n个权值,则构造出的哈夫曼树有n个叶⼦结点。
n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为:(1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有⼀个结点);(2) 在森林中选出两个根结点的权值最⼩的树合并,作为⼀棵新树的左、右⼦树,且新树的根结点权值为其左、右⼦树根结点权值之和;(3)从森林中删除选取的两棵树,并将新树加⼊森林;(4)重复(2)、(3)步,直到森林中只剩⼀棵树为⽌,该树即为所求得的哈夫曼树。
c代码过程分析构造哈夫曼树算法的实现可以分成两⼤部分:1、初始化:⾸先动态申请2n个单元;然后循环2n-1次,从1号单元开始,依次将1⾄2n-1所有单元中的双亲、左孩⼦、右孩⼦的下标都初始化为0;最后再循环n次,输⼊前n个单元中叶⼦节点的权值。
2、创建树:循环n-1次,通过n-1次的选择、删除与合并来创建哈夫曼树。
选择是从当前森林中选择双亲为0且权值最⼩的两个树跟节点是s1和s2;删除是指将节点s1和s2的双亲改为⾮0;合并就是将s1和s2的权值和作为⼀个新节点的权值依次存⼊到数组的第n+1之后的单元中,同时记录这个新节点左孩⼦的下标为s1,右孩⼦的下标为s2。
用Huffman树进行编码与解码算法

一、目的和要求1、通过本实验,熟悉二叉树、Huffman树的基本概念,掌握二叉树的存储结构及各种算法;2、熟悉用Huffman树进行电文的加密与解密算法。
二、实验内容1、Huffman树的存储方式;2、加密与解密算法在电文编码中的应用。
三、实验原理给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman tree)。
Huffman树是一种特殊的二叉树,其叶结点的编码是一种前缀码,同时,通过统计字符的频度,能够达到编码电文的最小化。
哈夫曼树的构造假设有n个权值,则构造出的哈夫曼树有n个叶子结点。
n个权值分别设为w1、w2、…、wn,则哈夫曼树的构造规则为:(1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);(2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;(3)从森林中删除选取的两棵树,并将新树加入森林;(4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。
四、实验步骤1、统计电文中字符的出现频率;2. 用统计频率建立Hffman树;3.生成前缀码;4.建立huffman树的解码算法;5.用随机输入的电文完成编码与解码过程。
五、程序源代码及注释#include<stdio.h>#include<malloc.h>#include<string.h>#include<stdio.h>#include<string.h>#include<malloc.h>typedef struct{int weight;unsigned int parent,lchild,rchild;char c;}Haffman;typedef struct {char a;int n;}cc;void input(char c[100],cc c1[100],int *n){int i,j,t,k,flag=0;i=strlen(c);c1[0].n=1;*n=1;c1[0].a=c[0];for(j=1;j<i;j++){for(t=0;t<*n;t++)if(c1[t].a==c[j]){flag=1;c1[t].n=c1[t].n+1;}if(flag!=1){c1[*n].n=1;c1[*n].a=c[j];*n=*n+1;}flag=0;}}void select(Haffman *ha,int *s1,int *s2,int n){int i,w=100;for(i=1;i<2*n;i++){if((ha+i)->parent==0&&(ha+i)->weight!=0)if((ha+i)->weight<w){*s1=i;w=(ha+i)->weight;}}(ha+(*s1))->parent=1;w=100;for(i=1;i<2*n;i++){if((ha+i)->parent==0&&(ha+i)->weight!=0)if((ha+i)->weight<w){*s2=i;w=(ha+i)->weight;}}(ha+(*s2))->parent=1;}void haffuman(char **c2, Haffman * haff,cc c1[100],int n) {int i,s1,s2,j,t;char *c;for(i=1;i<n+1;i++){(haff+i)->lchild=0;(haff+i)->parent=0;(haff+i)->rchild=0;(haff+i)->weight=c1[i-1].n;(haff+i)->c=c1[i-1].a;}for(i=1+n;i<2*n;i++){(haff+i)->lchild=0;(haff+i)->parent=0;(haff+i)->rchild=0;(haff+i)->weight=0;(haff+i)->c='\0';}for(i=n+1;i<2*n;i++){select(haff,&s1,&s2,n);(haff+i)->weight=(haff+s1)->weight+(haff+s2)->weight;(haff+i)->lchild=s1;(haff+i)->rchild=s2;(haff+s1)->parent=i;(haff+s2)->parent=i;}c=(char*)malloc(10*sizeof(char));for(i=1;i<=n;i++){t=i;j=9;*(c+j)='\0';while((haff+t)->parent!=0){j=j-1;if((haff+(haff+t)->parent)->lchild==t)*(c+j)='0';else*(c+j)='1';t=(haff+t)->parent;}*(c2+i)=(char*)malloc((10-j)*sizeof(char));strcpy(*(c2+i),(c+j));}}void main(){Haffman *haff;char **c2;cc c1[100];int i, n=0;char c[100];printf("请输入电文\n");scanf("%s",&c);input(c,c1,&n);haff=(Haffman *)malloc(2*n*sizeof(Haffman ));c2=(char**)malloc((n+1)*sizeof(char *));haffuman(c2, haff, c1,n);printf("字符权编码 \n");for(i=1;i<=n;i++){printf("%c ",(haff+i)->c);printf("%d ",(haff+i)->weight);printf("%s\n", *(c2+i));printf("\n");}}程序运行截图:。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
哈夫曼树构造算法
1、给定一个具有n个权值{ w1,w2,………wn }的结点的集合
F = { T1,T2,………Tn }
2、 初始时,设集合 A = F。 3、 执行 i = 1 至 n -1 的循环,在每次循环时执行以下操作
从当前集合中选取权值最小、次最小的两个结点,以这两个 结点作为内部结点 bi 的左右儿子,bi 的权值为其左右儿子 权值之和。 在集合中去除这两个权值最小、次最小的结点,并将内部结 点bI 加入其中。这样,在集合A中结点个数便减少了一个。
第 9 页
2011年10月
计算机科学与工程学院 TCS.CQ
a(10), e(15), i(12), s(3), t(4), 空格(13), 换行(1)。
a 10 a 10 e 15 e 15 i 12 i 12 S 3 t 4 t 4 空格 13 S 3 8 a 10 e 15 i 12 空格 13 S 3
计算机科学与工程学院 TCS.CQ
2 5 i 12 空格 13 5 8 4
3 3 1 8 8 t 4 换行 1 a 10 e 15
3 3
1 8 8 4 S 3 t 4 换行 1
2 5 e 15 i 12 空格 13
3
S
a 10
《数据结构》课件
计算机科学与工程学院 TCS.CQ
第 12 页
哈夫曼编码 A 001
2011年10月 计算机科学与工程学院 TCS.CQ 第 7 页
前缀编码
字符只放在叶结点中,所以任何一个字符的编码 都不是同一字符集中另一个字符的编码的前缀。 利用赫夫曼树可以构造一种不等长的二进制编码, 并且构造所得的赫夫曼编码是一种最优前缀编码, 即使所传电文的总长度最短。 字符编码可以有不同的长度
前缀编码可被惟一解码
《数据结构》课件
计算机科学与工程学院 TCS.CQ
第8页
哈夫曼树是一棵最小 代价的二叉树,在这 棵树上,所有的字符 都包含在叶结点上。
要使得整棵树的代价 最小,显然权值大的 叶子应当尽量靠近树 根,权值小的叶子可 以适当离树根远一些。
对应的哈夫曼编码如下: 1:000 3:001 5:01 7:1
这样,在经过了n-1 次循环之后,集合A中只剩下了一个结 点,这个结点就是根结点。
《数据结构》课件 计算机科学与工程学院 TCS.CQ 第5页
给定权值w=(1,3,5,7)来构造一棵哈夫曼树 。
16 4 1 3 5 7 1 3 1 (a) (b) 5 7 4 3 (c) 9 5 1 7 4 3 (d) 9 5 7
计算机科学与工程学院 TCS.CQ
第 16 页
赫夫曼树的存储
在哈夫曼树中,每个要编码的元素是一个叶结点,其它
结点都是度数为2的节点 一旦给定了要编码的元素个数,由n0=n2+1可知哈夫曼 树的大小为2n-1 哈夫曼树可用一个大小为2n的数组来存储。0节点不用, 根存放在节点1。叶结点依次放在n+1到2n的位置 每个数组元素保存的信息:结点的数据、权值和父结点
第 20 页
赫夫曼树的构造算法
void CreateHT(HTNode ht[],int n) { int i,j,k,lnode,rnode; for (i=0;i<2*n-1;i++) for (i=n;i<2*n-1;i++) { min1=min2=32767; for (k=0;k<=i-1;k++) if (ht[k].parent==0) { /*未构造二叉树的结点中查找或者=-1*/ lnode=rnode=0; float min1,min2; ht[i].parent=ht[i].lchild=ht[i].rchild=0; /*所有结点的相关域置初值或者-1*/
和左右孩子的位置
《数据结构》课件
计算机科学与工程学院 TCS.CQ
第 17 页
用ht[]数组存放哈夫曼树,对于具有n个叶子结点的哈夫 曼树,总共有2n-1个结点。 其算法思路是: n个叶子结点只有data和weight域值,先将所有2n-1个结点 的 parent 、 lchild 和 rchild 域置为初值 -1( 或者 0) 。处理每个 非叶子结点ht[i](存放在ht[n]~ht[2n-2]中):从ht[0] ~ht[i-2] 中找出根结点 ( 即其 parent 域为 -1 或者为 0) 的最小的两个结 点 ht[lnode] 和 ht[rnode], 将 它 们 作 为 ht[i] 的 左 右 子 树,ht[lnode]和ht[rnode]的双亲结点置为ht[i],并且 ht[i].weight=ht[lnode].weight+ht[rnode].weight。 如此这样直到所有2n-1个非叶子结点处理完毕。
2011年10月
计算机科学与工程学院 TCS.CQ
第 21 页
根据哈夫曼树求对应的哈夫曼编码的算法如下:
void CreateHCode(HTNode ht[],HCode hcd[],int n) { int i,f,c; HCode hc; for (i=0;i<n;i++) /*根据哈夫曼树求哈夫曼编码*/
E 01
e i sp
I 10
S 00000 T 0001
a
t
Sp 11
Nl 00001
s
nl
总共用了146bit
《数据结构》课件 计算机科学与工程学院 TCS.CQ 第 13 页
题例: 已知权值 W={ 5, 6, 2, 9, 7 }
5 6
6 9
2 7
9 7
7
所有原始结点是有一个 根结点,五左右子树
hc.cd[hc.start--]='1'; c=f;f=ht[f].parent; } hc.start++; hcd[i]=hc; } /*start指向哈夫曼编码最开始字符*/ /*再对双亲结点进行同样的操作*/
}
2011年10月 计算机科学与工程学院 TCS.CQ 第 22 页
编码的产生
对每个结点,从叶子往根推进,是左枝加0,是右枝加1
构造一棵哈夫曼树的过程
2011年10月 计算机科学与工程学院 TCS.CQ 第 6 页
哈夫曼编码
具体构造方法如下:
设需要编码的字符集合为 {d1,d2,…,dn}, 各个字符在 电 文 中 出 现 的 次 数 集 合 为 {w1,w2,…,wn}, 以 d1,d2,…,dn作为叶结点 ,以 w1,w2,…,wn作为各根结点 到每个叶结点的权值构造一棵二叉树。规定哈夫曼 树中的左分支为0,右分支为1,则从根结点到每个叶结 点所经过的分支对应的 0和 1组成的序列便为该结点 对应字符的编码。 这样的编码称为哈夫曼编码。 哈夫曼编码的生成: 每个字符的编码是根节点到该 字符的路径;左枝为0,右枝为1
5 9
5
《数据结构》课件
2 13
7
2 6
7
第 14 页
计算机科学与工程学院 TCS.CQ
9
5
7
2 6
13
7 0 0 6 00 13 1 7 01 29 0 9 10 1 16 0 5 110 1
7
《数据结构》课件
计算机科学与工程学院 TCS.CQ
第 15 页
1 2 111
哈夫曼树结点的数据结构(类型)
值 权 父 左 右 2 3 58 33 25 18 8 1 4 8 1 9 2 5 4 6 4 5 10 a e i s t 4 5 sp nl 13 1 3 6 10 15 12 3 4 2 3 6
WPL
w l
i 1
n
i i
其中 ,n 表示叶子结点数 ,wi 和 li 分别表示叶子结点 ki 的权值 和根到 ki之间的路径长度 (即从叶结点到根结点的分支数 )。 具有最小带权路径长度的二叉树称为哈夫曼树,又称 之为最优二差树。
2011年10月 计算机科学与工程学院 TCS.CQ 第 2 页
{ hc.start=n;c=i; f=ht[i].parent;
while (f!=-1) { if (ht[f].lchild==c) /*循环直到无双亲结点即到达树根结点*/ /*当前结点是左孩子结点*/
hc.cd[hc.start--]='0';
else
/*当前结点是双亲结点的右孩子结点*/
/*构造哈夫曼树*/ /*或者-1*/
if (ht[k].weight<min1) { min2=min1; rnode=lnode; min1=ht[k].weight;lnode=k; }
else if (ht[k].weight<min2) { } /*if*/ ht[lnode].parent=i;ht[rnode].parent=i; ht[i].weight=ht[lnode].weight+ht[rnode].weight; ht[i].lchild=lnode;ht[i].rchild=rnode; } } min2=ht[k].weight;rnode=k; }
生成过程分析
a e 15 2 i 12 3 s 3 6 t 4 5 sp 13 3 nl 1 6
3
值 权 父 左 右 0 2 3 1 58 33 1 4 8 2 25 1 9 12 3 18 2 5 7 4 8 4 6 11 5 4 5 10 13 6
10 4
7
8
9
10
11
12
13
《数据结构》课件
计算机科学与工程学院 TCS.CQ
《数据结构》课件 计算机科学与工程学院 TCS.CQ