实验四哈夫曼编码
哈夫曼编码译码实验报告

哈夫曼编码译码实验报告哈夫曼编码译码实验报告一、引言哈夫曼编码是一种用来对数据进行压缩的算法,它能够根据数据的频率分布来分配不同长度的编码,从而实现对数据的高效压缩。
本次实验旨在通过实际操作,深入理解哈夫曼编码的原理和实现方式,并通过编码和解码过程来验证其有效性。
二、实验目的1. 掌握哈夫曼编码的原理和算法;2. 学会使用编程语言实现哈夫曼编码和解码;3. 验证哈夫曼编码在数据压缩中的实际效果。
三、实验过程1. 数据准备在实验开始前,首先需要准备一段文本数据作为实验材料。
为了更好地展示哈夫曼编码的效果,我们选择了一篇新闻报道作为实验文本。
这篇报道涵盖了多个领域的信息,包括科技、经济、体育等,具有一定的复杂性。
2. 哈夫曼编码实现根据哈夫曼编码的原理,我们首先需要统计文本中每个字符的频率。
为了方便处理,我们将每个字符与其频率构建成一个字符-频率的映射表。
然后,我们根据频率构建哈夫曼树,将频率较低的字符作为叶子节点,频率较高的字符作为内部节点。
最后,根据哈夫曼树构建编码表,将每个字符映射到对应的二进制编码。
3. 哈夫曼解码实现在哈夫曼解码过程中,我们需要根据编码表将二进制编码转换回字符。
为了实现高效解码,我们可以将编码表转换为一个二叉树,其中每个叶子节点对应一个字符。
通过遍历二叉树,我们可以根据输入的二进制编码逐步还原出原始文本。
4. 编码和解码效果验证为了验证哈夫曼编码的有效性,我们需要对编码和解码的结果进行比较。
通过计算编码后的二进制数据长度和原始文本长度的比值,我们可以得到压缩率,进一步评估哈夫曼编码的效果。
四、实验结果经过实验,我们得到了以下结果:1. 哈夫曼编码表根据实验文本统计得到的字符-频率映射表,我们构建了哈夫曼树,并生成了相应的编码表。
编码表中每个字符对应的编码长度不同,频率较高的字符编码长度较短,频率较低的字符编码长度较长。
2. 编码结果将实验文本使用哈夫曼编码进行压缩后,得到了一串二进制数据。
《哈夫曼编码》实验报告

《哈夫曼编码》实验报告《哈夫曼编码》实验报告一、实验目的1、掌握哈夫曼编码原理;2、熟练掌握哈夫曼树的生成方法;3、理解数据编码压缩和译码输出编码的实现。
二、实验要求实现哈夫曼编码和译码的生成算法。
三、实验步骤编写代码如下:#include#include#include#define MAXLEN 100typedef struct{int weight;int lchild;int rchild;int parent;char key;}htnode;typedef htnode hfmt[MAXLEN];int n;void inithfmt(hfmt t){int i;printf("\n");printf("--------------------------------------------------------\n"); printf("**********************输入区**********************\n");printf("\n请输入n=");scanf("%d",&n);getchar();for(i=0;i<2*n-1;i++){t[i].weight=0;t[i].lchild=-1;t[i].rchild=-1;t[i].parent=-1;}printf("\n");}void inputweight(hfmt t){int w;int i;char k;for(i=0;i<n;i++)< bdsfid="112" p=""></n;i++)<>{printf("请输入第%d个字符:",i+1);scanf("%c",&k);getchar();t[i].key=k;printf("请输入第%d个字符的权值:",i+1);scanf("%d",&w);getchar();t[i].weight=w;printf("\n");}}void selectmin(hfmt t,int i,int *p1,int *p2){long min1=999999;long min2=999999;int j;for(j=0;j<=i;j++)if(t[j].parent==-1)if(min1>t[j].weight){min1=t[j].weight;*p1=j;}for(j=0;j<=i;j++)if(t[j].parent==-1)if(min2>t[j].weight && j!=(*p1))//注意 j!=(*p1)) { min2=t[j].weight;*p2=j;}}void creathfmt(hfmt t){int i,p1,p2;inithfmt(t);inputweight(t);for(i=n;i<2*n-1;i++){selectmin(t,i-1,&p1,&p2);t[p1].parent=i;t[p2].parent=i;t[i].lchild=p1;t[i].rchild=p2;t[i].weight=t[p1].weight+t[p2].weight;}}void printhfmt(hfmt t){int i;printf("------------------------------------------------------------------\n");printf("**************哈夫曼编数结构:*********************\n"); printf("\t\t权重\t父母\t左孩子\t右孩子\t字符\t");for(i=0;i<2*n-1;i++){printf("\n");printf("\t\t%d\t%d\t%d\t%d\t%c",t[i].weight,t[i].parent,t[i].lc hild,t [i].rchild,t[i].key);}printf("\n------------------------------------------------------------------\n");printf("\n\n");}void hfmtpath(hfmt t,int i,int j){int a,b;a=i;b=j=t[i].parent;if(t[j].parent!=-1){i=j;hfmtpath(t,i,j);}if(t[b].lchild==a)printf("0");elseprintf("1");}void phfmnode(hfmt t){int i,j,a;printf("\n---------------------------------------------\n"); printf("******************哈夫曼编码**********************"); for(i=0;i<n;i++)< bdsfid="190" p=""></n;i++)<>{j=0;printf("\n");printf("\t\t%c\t",t[i].key,t[i].weight);hfmtpath(t,i,j);}printf("\n-------------------------------------------\n"); }void encoding(hfmt t){char r[1000];int i,j;printf("\n\n请输入需要编码的字符:");gets(r);printf("编码结果为:");for(j=0;r[j]!='\0';j++)for(i=0;i<n;i++)< bdsfid="207" p=""></n;i++)<>if(r[j]==t[i].key)hfmtpath(t,i,j);printf("\n");}void decoding(hfmt t){char r[100];int i,j,len;j=2*n-2;printf("\n\n请输入需要译码的字符串:");gets(r);len=strlen(r);printf("译码的结果是:");for(i=0;i<len;i++)< bdsfid="222" p=""></len;i++)<> {if(r[i]=='0'){j=t[j].lchild;if(t[j].lchild==-1){printf("%c",t[j].key);j=2*n-2;}}else if(r[i]=='1'){j=t[j].rchild;if(t[j].rchild==-1){printf("%c",t[j].key);j=2*n-2;}}printf("\n\n");}int main(){int i,j;hfmt ht;char flag;printf("\n----------------------------------------------\n");printf("*******************编码&&译码&&退出***************");printf("\n【1】编码\t【2】\t译码\t【0】退出");printf("\n您的选择:");flag=getchar();getchar();while(flag!='0'){if(flag=='1')encoding(ht);else if(flag=='2')decoding(ht);elseprintf("您的输入有误,请重新输入。
哈夫曼编码的实验报告

哈夫曼编码的实验报告哈夫曼编码的实验报告一、引言信息的传输和存储是现代社会中不可或缺的一部分。
然而,随着信息量的不断增加,如何高效地表示和压缩信息成为了一个重要的问题。
在这个实验报告中,我们将探讨哈夫曼编码这一种高效的信息压缩算法。
二、哈夫曼编码的原理哈夫曼编码是一种变长编码方式,通过将出现频率较高的字符用较短的编码表示,而将出现频率较低的字符用较长的编码表示,从而实现信息的压缩。
它的核心思想是利用统计特性,将出现频率较高的字符用较短的编码表示,从而减少整体编码长度。
三、实验过程1. 统计字符频率在实验中,我们首先需要统计待压缩的文本中各个字符的出现频率。
通过遍历文本,我们可以得到每个字符出现的次数。
2. 构建哈夫曼树根据字符频率,我们可以构建哈夫曼树。
哈夫曼树是一种特殊的二叉树,其中每个叶子节点代表一个字符,并且叶子节点的权值与字符的频率相关。
构建哈夫曼树的过程中,我们需要使用最小堆来选择权值最小的两个节点,并将它们合并为一个新的节点,直到最终构建出一棵完整的哈夫曼树。
3. 生成编码表通过遍历哈夫曼树,我们可以得到每个字符对应的编码。
在遍历过程中,我们记录下每个字符的路径,左边走为0,右边走为1,从而生成编码表。
4. 进行编码和解码在得到编码表后,我们可以将原始文本进行编码,将每个字符替换为对应的编码。
编码后的文本长度将会大大减少。
为了验证编码的正确性,我们还需要进行解码,将编码后的文本还原为原始文本。
四、实验结果我们选取了一段英文文本作为实验数据,并进行了哈夫曼编码。
经过编码后,原始文本长度从1000个字符减少到了500个字符。
解码后的文本与原始文本完全一致,验证了哈夫曼编码的正确性。
五、讨论与总结哈夫曼编码作为一种高效的信息压缩算法,具有广泛的应用前景。
通过将出现频率较高的字符用较短的编码表示,哈夫曼编码可以在一定程度上减小信息的存储和传输成本。
然而,哈夫曼编码也存在一些局限性,例如对于出现频率相近的字符,编码长度可能会相差较大。
实验四 哈弗曼编码

实验四、哈夫曼编码实验目的掌握哈夫曼编码的原理,并编出最优编码实验环境C语言读写文件实验内容先根据位权构造一颗哈夫曼树,测试数据0.05 0.1 0.15 0.2 0.25 0.25,再从叶子结点到根结点编码。
源代码实验结果实验总结源代码#include <stdio.h>#include <string.h>#include<stdlib.h>#define N 50 /*叶子结点数*/#define M 2*N-1 /*树中结点总数*/typedef struct{char data[5]; /*结点值*/float weight; /*权重*/float parent; /*双亲结点*/float lchild; /*左孩子结点*/float rchild; /*右孩子结点*/} HTNode;typedef struct{char cd[N]; /*存放哈夫曼码*/int start;} HCode;void CreateHT(HTNode ht[],int n){int i,k,lnode,rnode;float min1,min2;for (i=0;i<2*n-1;i++) /*所有结点的相关域置初值-1*/ht[i].parent=ht[i].lchild=ht[i].rchild=-1;for (i=n;i<2*n-1;i++) /*构造哈夫曼树*/{min1=min2=32767; /*lnode和rnode为最小权重的两个结点位置*/ lnode=rnode=-1;for (k=0;k<=i-1;k++)if (ht[k].parent==-1) /*只在尚未构造二叉树的结点中查找*/{if (ht[k].weight<min1){min2=min1;rnode=lnode;min1=ht[k].weight;lnode=k;}else if (ht[k].weight<min2){min2=ht[k].weight;rnode=k;}}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;}}void CreateHCode(HTNode ht[],HCode hcd[],int n) {int i,f,c;HCode hc;for (i=0;i<n;i++) /*根据哈夫曼树求哈夫曼编码*/ {hc.start=n;c=i;f=ht[i].parent;while (f!=-1) /*循序直到树根结点*/{if (ht[f].lchild==c) /*处理左孩子结点*/hc.cd[hc.start--]='0';else /*处理右孩子结点*/hc.cd[hc.start--]='1';c=f;f=ht[f].parent;}hc.start++; /*start指向哈夫曼编码最开始字符*/ hcd[i]=hc;}}void main(){int n=6,i,k;float sum=0,m=0,j;float fnum[6];HTNode ht[M];HCode hcd[N];char *str[]={"a0","a1","a2","a3","a4","a5"};//float fnum[]={0.05,0.1,0.15,0.2,0.25,0.25};FILE *fp;if((fp=fopen("H:\\study\\C++\\file\\hafuman.txt","r+"))==NULL) {printf("不能打开文件!\n");exit(1);}for(i=0;i<n;i++)fscanf(fp,"%f",&fnum[i]);//原始文件的输出fseek(fp,0,2);//for(i=0;i<n;i++)//{// printf("%5.2f ",fnum[i]);//}//printf("\n");printf("\n赋值给字符:");fprintf(fp,"\n赋值给字符:");for(i=0;i<n;i++){printf("\n%s=%.2f ",str[i],fnum[i]);fprintf(fp,"\n%s=%.2f ",str[i],fnum[i]);}for (i=0;i<n;i++){strcpy(ht[i].data,str[i]);ht[i].weight=fnum[i];}printf("\n");CreateHT(ht,n);CreateHCode(ht,hcd,n);// DispHCode(ht,hcd,n);printf("输出哈夫曼编码:\n"); /*输出哈夫曼编码*/fprintf(fp,"\n输出哈夫曼编码:\n");for (i=0;i<n;i++){j=0;printf(" %s:\t",ht[i].data);fprintf(fp," %s:\t",ht[i].data);for (k=hcd[i].start;k<=n;k++){printf("%c",hcd[i].cd[k]);fprintf(fp,"%c",hcd[i].cd[k]);j++;}m+=ht[i].weight;sum+=ht[i].weight*j;printf("\n");fprintf(fp,"\n");}printf("\n 平均长度=%.2f\n",sum/m);fprintf(fp,"\n 平均长度=%.2f\n",sum/m);printf("\n");fprintf(fp,"\n");fclose(fp);}测试结果:0.05 0.10 0.15 0.2 0.25 0.25(最开始写入的数据)赋值给字符:a0=0.05a1=0.10a2=0.15a3=0.20a4=0.25a5=0.25输出哈夫曼编码:a0: 1110a1: 1111a2: 110a3: 00a4: 01a5: 10平均长度=2.45。
哈夫曼树编码实验报告

哈夫曼树编码实验报告哈夫曼树编码实验报告引言:哈夫曼树编码是一种常用的数据压缩算法,通过对数据进行编码和解码,可以有效地减小数据的存储空间。
本次实验旨在探究哈夫曼树编码的原理和应用,并通过实际案例验证其有效性。
一、哈夫曼树编码原理哈夫曼树编码是一种变长编码方式,根据字符出现的频率来确定不同字符的编码长度。
频率较高的字符编码较短,频率较低的字符编码较长,以达到最佳的数据压缩效果。
1.1 字符频率统计首先,需要对待编码的数据进行字符频率统计。
通过扫描数据,记录每个字符出现的次数,得到字符频率。
1.2 构建哈夫曼树根据字符频率构建哈夫曼树,频率较低的字符作为叶子节点,频率较高的字符作为父节点。
构建哈夫曼树的过程中,需要使用最小堆来维护节点的顺序。
1.3 生成编码表通过遍历哈夫曼树,从根节点到每个叶子节点的路径上的左右分支分别赋予0和1,生成对应的编码表。
1.4 数据编码根据生成的编码表,将待编码的数据进行替换,将每个字符替换为对应的编码。
编码后的数据长度通常会减小,实现了数据的压缩。
1.5 数据解码利用生成的编码表,将编码后的数据进行解码,恢复原始数据。
二、实验过程与结果为了验证哈夫曼树编码的有效性,我们选择了一段文本作为实验数据,并进行了以下步骤:2.1 字符频率统计通过扫描文本,统计每个字符出现的频率。
我们得到了一个字符频率表,其中包含了文本中出现的字符及其对应的频率。
2.2 构建哈夫曼树根据字符频率表,我们使用最小堆构建了哈夫曼树。
频率较低的字符作为叶子节点,频率较高的字符作为父节点。
最终得到了一棵哈夫曼树。
2.3 生成编码表通过遍历哈夫曼树,我们生成了对应的编码表。
编码表中包含了每个字符的编码,用0和1表示。
2.4 数据编码将待编码的文本数据进行替换,将每个字符替换为对应的编码。
编码后的数据长度明显减小,实现了数据的压缩。
2.5 数据解码利用生成的编码表,将编码后的数据进行解码,恢复原始文本数据。
四元霍夫曼编码的例子

四元霍夫曼编码的例子一、四元霍夫曼编码简介四元霍夫曼编码(Quaternary Huffman Code)是一种基于霍夫曼编码的编码方式,由美国计算机科学家David A.Huffman于1952年提出。
它是霍夫曼编码的一种扩展,采用四个符号(0、1、2、3)来表示输入字符的频率,以提高编码效率。
在实际应用中,四元霍夫曼编码常用于数据压缩、信息传输和数据库管理等领域。
二、四元霍夫曼编码的计算方法1.码字长度计算四元霍夫曼编码的码字长度计算方法与二元霍夫曼编码相似,仍然是根据输入字符的频率来确定码字长度。
不同的是,四元霍夫曼编码采用四个符号表示频率,因此码字长度有4种可能:1、2、3、4。
2.码字分配原则在分配码字时,四元霍夫曼编码遵循以下原则:1) 频率低的字符分配较短的码字;2) 频率高的字符分配较长的码字;3) 相邻字符的码字不能相同。
3.编码过程演示以字符“A”为例,其频率为1/4(假设四个字符中有一个是“A”):1) 初始化四个码字:0000、0001、0010、0011;2) 将码字0000分配给字符“A”;3) 更新剩余字符的码字:0001、0010、0011;4) 重复步骤2和3,直到所有字符都分配到码字;5) 得到最终的码字表。
三、四元霍夫曼编码的应用1.数据压缩四元霍夫曼编码可用于压缩原始数据,将字符映射到对应的码字。
压缩后的数据可用于存储、传输和检索。
在解码过程中,根据码字还原原始数据。
2.信息传输在信息传输过程中,四元霍夫曼编码可确保数据的可靠性。
通过编码和解码,接收方可以正确还原发送方的原始信息。
3.数据库管理在数据库管理中,四元霍夫曼编码可用于索引、排序和查找等操作。
通过编码,可以提高数据检索的速度和准确性。
四、四元霍夫曼编码的优缺点1.优点- 编码效率高:相较于二元霍夫曼编码,四元霍夫曼编码采用更多符号表示频率,可进一步提高编码效率;- 易于实现:四元霍夫曼编码的计算方法和二元霍夫曼编码相似,只需扩展符号集即可;- 可靠性高:四元霍夫曼编码具有较高的编码可靠性,可确保数据正确传输和解析。
数据结构哈夫曼编码实验报告

数据结构哈夫曼编码实验报告【正文】1.实验目的本实验旨在研究哈夫曼编码的原理和实现方法,通过实验验证哈夫曼编码在数据压缩中的有效性,并分析其应用场景和优缺点。
2.实验原理2.1 哈夫曼编码哈夫曼编码是一种无损数据压缩算法,通过根据字符出现的频率构建一颗哈夫曼树,将频率较高的字符用较短的编码表示,频率较低的字符用较长的编码表示。
哈夫曼编码的编码表是唯一的,且能够实现前缀编码,即一个编码不是另一个编码的前缀。
2.2 构建哈夫曼树构建哈夫曼树的过程如下:1) 将每个字符及其频率作为一个节点,构建一个节点集合。
2) 每次从节点集合中选择出现频率最低的两个节点,构建一个新节点,并将这两个节点从集合中删除。
3) 将新节点加入节点集合。
4) 重复以上步骤,直到节点集合中只有一个节点,这个节点就是哈夫曼树的根节点。
2.3 编码过程根据哈夫曼树,对每个字符进行编码:1) 从根节点开始,根据左子树为0,右子树为1的规则,将编码依次加入编码表。
2) 对于每个字符,根据编码表获取其编码。
3) 将编码存储起来,得到最终的编码序列。
3.实验步骤3.1 数据读取与统计从输入文件中读取字符序列,并统计各个字符的频率。
3.2 构建哈夫曼树根据字符频率构建哈夫曼树。
3.3 构建编码表根据哈夫曼树,构建每个字符的编码表。
3.4 进行编码根据编码表,对输入的字符序列进行编码。
3.5 进行解码根据哈夫曼树,对编码后的序列进行解码。
4.实验结果与分析4.1 压缩率分析计算原始数据和压缩后数据的比值,分析压缩率。
4.2 编码效率分析测试编码过程所需时间,分析编码效率。
4.3 解码效率分析测试解码过程所需时间,分析解码效率。
4.4 应用场景分析分析哈夫曼编码在实际应用中的优势和适用场景。
5.结论通过本次实验,我们深入了解了哈夫曼编码的原理和实现方法,实践了哈夫曼编码的过程,并对其在数据压缩中的有效性进行了验证。
实验结果表明,哈夫曼编码能够实现较高的压缩率和较高的编解码效率。
哈夫曼编码实验超详尽版

编码步骤
6
在F中选取两棵根结点权值最小的树作为新构造 的二叉树的左右子树,新二叉树的根结点的权 值为其左右子树的根结点的权值之和。 从F中删除这两棵树,并把这棵新的二叉树同样 以升序排列加入到集合F中。 重复二和三两步,直到集合F中只有一棵二叉树 为止。
示例
7
假如有A,B,C,D,E五个字符,出现的频率(即权值) 分别为5,4,3,2,1,那么我们第一步先取两个最小权值 作为左右子树构造一个新树,即取1,2构成新树, 其结点为1+2=3,如图:
原理
3
首先统计信源中各符号出现的概率,按符号出现的
概率从大到小排序; 把最小的两个概率相加合并成新的概率,与剩余的 概率组成新的概率集合; 对新的概率集合重新排序,再次把其中最小的两个 概率相加,组成新的概率集合。如此重复进行,直 到最后两个概率的和为l;原理4 Nhomakorabea
分配码字:码字分配从最后一步开始反向进行,
9
实现过程:首先通过 HuffmanTree() 函数构造哈夫 曼树,然后在主函数 main()中自底向上开始(也就 是从数组序号为零的结点开始)向上层层判断,若 在父结点左侧,则置码为 0,若在右侧,则置码为 1。 最后输出生成的编码。 typedef struct
{ int bit[MAXBIT]; int start; } HCodeType; /* 编码结构体 */
五、程序部分代码及其分析
13
/* 设置找到的两个子结点 x1、x2 的父结点信息 */ HuffNode[x1].parent = n+i; HuffNode[x2].parent = n+i; HuffNode[n+i].weight = HuffNode[x1].weight + HuffNode[x2].weight; HuffNode[n+i].lchild = x1; HuffNode[n+i].rchild = x2;
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验四 贪心算法
实验目的和要求
(1)了解前缀编码的概念,理解数据压缩的基本方法;
(2)掌握最优子结构性质的证明方法;
(3)掌握贪心法的设计思想并能熟练运用
(4)证明哈夫曼树满足最优子结构性质;
(5)设计贪心算法求解哈夫曼编码方案;
(6)设计测试数据,写出程序文档。
实验内容
设需要编码的字符集为{d 1, d 2, …, dn },它们出现的频率为 {w 1, w 2, …, wn },应用哈夫曼树构造最短的不等长编码方案。
实验环境
Dev c++
实验学时
2学时,必做实验
数据结构与算法
/*示例
****哈夫曼编码****
请输入结点个数:8
输入这8个元素的权值(均为整形):
1:27
2:4
3:87
4:21
5:2
6:21
7:1
8:25
*/
#include <stdio.h>
#include <stdlib.h>
∑=j
i k k a
#include <string.h>
typedef struct
{
unsigned int weight; //用来存储各个结点的权值
unsigned int parent,LChild,RChild; //指向双亲、孩子结点的指针} HTNode, *HuffmanTree; //动态分配数组,存储哈夫曼树
typedef char *HuffmanCode; //动态分配数组,存储哈夫曼树
///选择两个parent为0,且weight最小的结点s1和s2
void Select(HuffmanTree *ht,int n,int *s1,int *s2)
{
int i,min;
for(i=1; i<=n; i++)
{
if((*ht)[i].parent==0)
{
min=i;
break;
}
}
for(i=1; i<=n; i++)
{
if((*ht)[i].parent==0)
{
if((*ht)[i].weight<(*ht)[min].weight)
min=i;
}
}
*s1=min;
for(i=1; i<=n; i++)
{
if((*ht)[i].parent==0 && i!=(*s1))
{
min=i;
break;
}
}
for(i=1; i<=n; i++)
{
if((*ht)[i].parent==0 && i!=(*s1))
{
if((*ht)[i].weight<(*ht)[min].weight)
min=i;
}
}
*s2=min;
}
///构造哈夫曼树ht,w存放已知n个权值
void CrtHuffmanTree(HuffmanTree *ht,int *w,int n) {
int m,i,s1,s2;
m=2*n-1; //总共的结点数
*ht=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); for(i=1; i<=n; i++) //1-n号存放叶子结点,初始化 {
(*ht)[i].weight=w[i];
(*ht)[i].LChild=0;
(*ht)[i].parent=0;
(*ht)[i].RChild=0;
}
for(i=n+1; i<=m; i++) //非叶子结点的初始化
{
(*ht)[i].weight=0;
(*ht)[i].LChild=0;
(*ht)[i].parent=0;
(*ht)[i].RChild=0;
}
printf("\n?哈夫曼树为: \n");
for(i=n+1; i<=m; i++) //创建非叶子结点,建哈夫曼树
{ /*在(*ht)[1]~(*ht)[i-1]的范围内选择两个parent为0且weight最小的结点,其序号分别赋值给s1、s2*/
Select(ht,i-1,&s1,&s2);
(*ht)[s1].parent=i;
(*ht)[s2].parent=i;
(*ht)[i].LChild=s1;
(*ht)[i].RChild=s2;
(*ht)[i].weight=(*ht)[s1].weight+(*ht)[s2].weight;
printf("%d (%d, %d)\n",(*ht)[i].weight,(*ht)[s1].weight,(*ht)[s2].weight);
}
printf("\n");
}
//从叶子结点到根,逆向求每个叶子结点对应的哈夫曼编码
void CrtHuffmanCode(HuffmanTree *ht, HuffmanCode *hc, int n)
{
char *cd; //定义的存放编码的空间
int a[100];
int i,start,p,w=0;
unsigned int c;
hc=(HuffmanCode *)malloc((n+1)*sizeof(char *)); //分配n个编码的头指针
cd=(char *)malloc(n*sizeof(char)); //分配求当前编码的工作空间
cd[n-1]='\0'; //从右向左逐位存放编码,首先存放编码结束符
for(i=1; i<=n; i++) //求n个叶子结点对应的哈夫曼编码
{
a[i]=0;
start=n-1; //起始指针位置在最右边
for(c=i,p=(*ht)[i].parent; p!=0; c=p,p=(*ht)[p].parent) //从叶子到根结点求编码 {
if( (*ht)[p].LChild==c)
{
cd[--start]='1'; //左分支标1
a[i]++;
}
else
{
cd[--start]='0'; //右分支标0
a[i]++;
}
}
hc[i]=(char *)malloc((n-start)*sizeof(char)); //为第i个编码分配空间
strcpy(hc[i],&cd[start]); //将cd复制编码到hc
}
free(cd);
for(i=1; i<=n; i++)
printf(" 权值为%d的哈夫曼编码为:%s\n",(*ht)[i].weight,hc[i]);
for(i=1; i<=n; i++)
w+=(*ht)[i].weight*a[i];
printf(" 带权路径为:%d\n",w);
}
int main()
{
HuffmanTree HT;
HuffmanCode HC;
int *w,i,n,wei;
printf("**哈夫曼编码**\n" );
printf("请输入结点个数:" );
scanf("%d",&n);
w=(int *)malloc((n+1)*sizeof(int));
printf("\n输入这%d个元素的权值:\n",n);
for(i=1; i<=n; i++)
{
printf("%d: ",i);
fflush(stdin);
scanf("%d",&wei);
w[i]=wei;
}
CrtHuffmanTree(&HT,w,n);
CrtHuffmanCode(&HT,&HC,n);
system("pause");
return 0;
}
实验结果
实验体会。