哈夫曼编译码器.docx
- 文档编号:6872725
- 上传时间:2023-01-11
- 格式:DOCX
- 页数:22
- 大小:172.18KB
哈夫曼编译码器.docx
《哈夫曼编译码器.docx》由会员分享,可在线阅读,更多相关《哈夫曼编译码器.docx(22页珍藏版)》请在冰豆网上搜索。
哈夫曼编译码器
摘要
哈夫曼在上世纪五十年代初就提出这种编码时,根据字符出现的概率来构造平均长度最短的编码。
它是一种变长的编码。
在编码中,若各码字长度严格按照码字所对应符号出现概率的大小的逆序排列,则编码的平均长度是最小的。
(注:
码字即为符号经哈夫曼编码后得到的编码,其长度是因符号出现的概率而不同,所以说哈夫曼编码是变长的编码。
)
由于哈夫曼给出了构造这种树的规律,将给定结点构成一棵带权树的路径长度最小的二叉数,因此称为哈夫曼树。
本程序利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。
对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。
本程序就是为这样的信息收发站写的一个哈夫曼码的编/译码系统。
关键词:
哈夫曼;编码;紧凑码;最优二叉树
Abstract
Huffmanintheearlyfiftycenturycameupwiththiscode,toconstructtheshortestaveragelengthcodingaccordingtotheprobabilityofcharacters.Itisavariablelengthcode.Inthecode,ifthecodelengthinstrictaccordancewiththecodewordcorrespondingtotheprobabilityofsymbolappearsarrangedinreverse,theaveragelengthofthecodeisthesmallest.(Note:
thewordisthesymboloftheHuffmancodingbycoding,itslengthisbecausethesymboloccurrenceprobabilityanddifferent,sothattheHuffmancodeisavariablelengthcode.)
BecauseHuffmangivesthestructureofthistreerules,willbegivennodesformaweightedpathlengthoftreewithminimumnumberoftwofork,soitiscalledtheHuffmantree.
TheproceduresfortheuseofHuffmancodingcangreatlyimprovethecommunicationchannelutilization,reducetheinformationtransmissiontime,lowertransmissioncosts.However,thisrequiresthesendingendthroughacodingsystemforpreencodeddata,atthereceivingendofdatafromthedecoding(FuYuan).Forduplexchannel(whichcanbeatwo-waychanneltotransmitinformation),eachsideneedsacompleteencoding/decodingsystem.ThisprogramisforsuchaHuffmancodeinformationtransceiverstationtowritetheencoding/decodingsystem.
Keywords:
Huffman;codingcompact;codeoptimal
1绪论
1.1课程设计的目的
课程设计是《数据结构》课程教学必不可缺的一个重要环节,可加深对该课程所学内容的进一步的理解与巩固,是将计算机课程与实际问题相联接的关键步骤。
通过课程设计,能够提高分析问题、解决问题,从而运用所学知识解决实际问题的能力,因而必须给予足够的重视。
1.2课程设计的需求和意义
1.2.1课程设计的需求
●理论研究基础
a.利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。
对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。
试为这样的信息收发站写一个哈夫曼码的编/译码系统。
通过该题目的设计过程,可以加深理解树及二叉树的逻辑结构、存储结构,掌握树及二叉树上基本运算的实现。
进一步理解和熟练掌握课本中所学的各种数据结构,学会如何把学到的知识用于解决实际问题,培养学生的动手能力。
b.面向对象程序设计的基本思路和方法。
●技术层面的支持
a.数据结构与算法分析,如队列“先进先出”的数据结构,线性表顺序存储的随机访问和链式存储的顺序访问的特点,最优二叉树(哈夫曼树)的建立使WPL(带权路径长度)最小;结构体定义、结构体数组、全局变量、二进制文件的创建等方法的使用。
b.以Visual C++为主要编程语言,运用其中的编程思想和主要算法以及其提供的面向对象机制。
1.2.2课程设计的意义
就一般情况而言,课程设计要比教学实验复杂一些,涉及的知识层面更深、更广,而且更加实用。
同时通过课程设计的综合训练,培养分析、解决实际问题和编程等动手操作的能力,最终通过这种形式,帮助同学的掌握数据结构这门课程。
结合实际应用的要求,使课程设计既覆盖教学所要求的知识点,又接近工程的实际需要,训练自己实际分析问题和解决问题以及编程的能力。
通过实例分析,循环渐进的描述,启发顺利的完成设计。
课程设计将设计要求、需求分析、系统设计、系统实现和系统测试运行分开,为创造分析问题、独立思考的条件。
只要在吃透要求和算法的前提下,完全可以自己设计出更具有特色的程序。
2
概要设计
2.1功能模块图
根据哈夫曼编码编码器要求可以得出功能模块图为:
输入一个字符串用结构体链表存储字符串中出现的不同字符及其出现的次数。
定义哈夫曼数的结点结构体,把不同的字符及其在字符串中出现的次数作为叶子结点的元素及其权值,统计叶子结点的个数n,开辟可以存储2*n个结点的顺序表,来哈夫曼树的各个结点,然后按照一定的规则构造哈夫曼树。
开辟一个可以存储叶子结点元素及指向存储其哈夫曼编码链表的指针的顺序表,然后从叶子结点开始向上访问,是左孩子的把“0”接进链表是右孩子的把“1”接进链表,直到根结点,然后把叶子结点的元素及存储其哈夫曼链表的头指针读入顺序表,直到把所有的叶子结点的元素及指向存储其哈夫曼编码链表的头指针读入顺序表,这样得到的哈夫曼编码是倒序的。
从存储其叶子结点及指向存储其哈夫曼编码链表头指针的顺序表表头开始顺序访问各元素,在输出其哈夫曼编码之前,把链表中的编码顺序读入到等长的栈中,然后编码出栈就会得到顺序的哈夫曼编码,直到把所有的叶子结点都访问到。
用一个字符型的指针指向字符串的第一个字符,从存储叶子结点元素及指向存储其哈夫曼编码链表的头指针的顺序表表头开始访问顺序表中的各元素,直到找到叶子结点的元素和当前字符相等就结束访输出哈夫曼编码,回到表头,指针后移,直到输出字符串的最后一个字符的哈夫曼编码,这样就得到输入字符串的哈夫曼编码。
3各函数所实现的功能
3.1intmain()
主函数:
利用已建好的哈夫曼树(如不在内存,则从文件hfmtree.txt中读入)对文件中的正文进行编码
然后将结果存入文件codefile.txt中。
如果正文中没有要编码的字符,则键盘读入并存储到ToBeTran文件中。
读入ToBeTran中将要编码的内容,将编码好的哈夫曼编码存储到CodeFile中。
(流程图见2.2)
3.2voidhfmcoding
初始化哈夫曼树,处理InputHuffman(HuffmanHfm)函数得到的数据,按照哈夫曼规则建立二叉树。
此函数块调用了Select()函数。
(流程图2.3)
voidhfmcoding(hfmtree&HT,hfmcode&HC,intn)//构建哈夫曼树HT,并求出n个字符的哈夫曼编码HC
{
inti,start,c,f,m,w;
intp1,p2;
char*cd,z;
if(n<=1){
return;
}
m=2*n-1;
HT=(hfmtree)malloc((m+1)*sizeof(htnode));
for(i=1;i<=n;++i)//初始化n个叶子结点
{
printf("请输入第%d字符信息和权值:
",i);
scanf("%c%d",&z,&w);
while(getchar()!
='\n')
{
continue;
}
HT[i].ch=z;
HT[i].weight=w;
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;
}
for(;i<=m;++i)//初始化其余的结点
{
HT[i].ch='0';
HT[i].weight=0;
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;
}
for(i=n+1;i<=m;++i)//建立哈夫曼树
{
Select(HT,i-1,&p1,&p2);
HT[p1].parent=i;HT[p2].parent=i;
HT[i].lchild=p1;HT[i].rchild=p2;
HT[i].weight=HT[p1].weight+HT[p2].weight;
}
HC=(hfmcode)malloc((n+1)*sizeof(char*));
cd=(char*)malloc(n*sizeof(char));
cd[n-1]='\0';
for(i=1;i<=n;++i)//给n个字符编码
{
start=n-1;
for(c=i,f=HT[i].parent;f!
=0;c=f,f=HT[f].parent)
{
if(HT[f].lchild==c)
{
cd[--start]='0';
}
else
{
cd[--start]='1';
}
}
HC[i]=(char*)malloc((n-start)*sizeof(char));
strcpy(HC[i],&cd[start]);
}
free(cd);
}
3.3voidSelect
Select函数,选出HT树到a为止,权值最小且parent为0的2个节点
voidSelect(hfmtree&HT,inta,int*p1,int*p2)//Select函数,选出HT树到a为止,权值最小且parent为0的2个节点
{
inti,j,x,y;
for(j=1;j<=a;++j){
if(HT[j].parent==0){
x=j;
break;
}
}
for(i=j+1;i<=a;++i){
if(HT[i].weight x=i;//选出最小的节点 } } for(j=1;j<=a;++j){ if(HT[j].parent==0&&x! =j) { y=j; break; } } for(i=j+1;i<=a;++i) { if(HT[i].weight =i) { y=i;//选出次小的节点 } } if(x>y){ *p1=y; *p2=x; } else { *p1=x; *p2=y; } } ●Encoding 编码功能: 对输入字符进行编码 ●Decoding 译码功能: 利用已建好的哈夫曼树将文件codefile.txt中的代码进行译码,结果存入文件textfile.dat中。 Print()打印功能函数: 输出哈夫曼树,字符,权值,以及它对应的编码。 ●使用链树存储,然后分别调用统计频数函数,排序函数,建立哈夫曼函数,编码函数,译码函数来实现功能。 ●哈夫曼树节点的数据类型定义为: 图4.2intmain函数 typedefstruct{//哈夫曼树的结构体 charch; intweight;//权值 intparent,lchild,rchild; }htnode,*hfmtree; weight是其权值,lchild为另一节点即左孩子的序号,同理rchild为另一节点即右孩子的序号,而parent为该节点的父节点的序号。 4调试分析 4.1调试中遇到的问题及对问题的解决方法 在我们课程设计时,就在编写好源代码后的调试过程中出现了不少的错误,遇到了很多麻烦及困难,我们的调试中的错误和我们最终找出错误,修改为正确的能够执行的程序中,通过分析,我们学到了: 在定义头文件时可多不可少,即我们可多写些头文件,肯定不会出错,但是若没有定义所引用的相关头文件,必定调试不通过; 在执行译码操作时,不知什么原因,总是不能把要编译的二进制数与编译成的字符用连接号连接起来,而是按顺序直接放在一起,视觉效果不是很好。 还有就是刚开始我们组模块化意识模糊,出现在调试中的许多不必要的麻烦,此次课程设计的最大收获就是让我们明白一个道理: 无论你做的是多么小的一个程序或软件,都要使用模块化设计,这样使程序实现的功能更清晰明了。 4.2算法的时间复杂度和空间复杂度 voidBianMa_all(HuffmanTreeHT,char**HC,char*filename)//整篇文章编码 HuffmanTreeCreateHuffman(HuffmanTree&HT,structnode*w,intn)//建立哈夫曼树 这两个被调函数里面都用了三重循环,其他的调用函数或者主函数都是一重或二重循环,所以算法复杂度为O(n3)。 可以看出此算法效率是比较低的,希望能够找出更好的算法来减小复杂度。 4.3测试用例及结果 1.初始化界面 2. 信息录入: 输入信息A~Z和其权值 3. 编码: 输入单个字符A然后输入字符串THISPROGRAMISMYFOVRITE 4.译码 5.异常处理: 当输入不为I、E、D、Q 6.退出: 输入Q 5总结 经过这次两周的编程实践,我学习到了很多东西。 首先,是对C语言有了更深一层次的认识,在这之前,C语言一直是头痛的问题,通过实践,我认识到C语言的问题其实并不是难度上的问题,终点在于动手方面,以前挺了就过了,对C语言其实非常的生疏,没有通过更多实践去做,就是很难掌握的,反之,就很容易了解它的规律,也就很容易上手了,所以,归根到底都是练习问题。 另一方面让我对程序设计有了一个比较直观的认识了,说实话,在这之前,虽然学习了接近两年了,但对程序这一事物始终是没有很多的了解,可以说没有入门。 虽然这次实践我得到了很多预期很不预期的成果,同时也发现了自己的很多不足,比如一方面使我认识到对程序全局设计的把握还不足,体现在刚开始设计程序时,总会考虑不周全,导致在后续设计中遇到了很多问题,不得不返回去修正充实前面已经完成的部分程序,而这个过程相当麻烦,因为前面已经做的往往牵扯到后面很多东西,效率是相当低的。 所以觉得设计程序这一部一定要多做准备,尽量把要遇到的问题考虑周全。 另一方面问题就是写程序的时候还比较粗心。 很多地方都是那种一般不太重视的、理所当然不应该犯错的,所以导致调试的时候要费很多功夫去改正,更遭的是很多时候错就在平时我们不屑一顾的方面,所以调试的时候也很难发现,就更加拖延了进度,导致效率极度地下。 因此这些困难都应通过以后的学习和努力改正和克服。 成果不是很大,这次课程设计收获很多,很值得我回忆,并在以后的学习之中借鉴。 最后,通过这次实践,我从整体了解到并掌握了一些程序方面的知识,不骄傲,不气馁,脚踏实地,细心、认真的学习我觉得这就是我最终需要的。 参考文献 [1]严蔚敏,吴伟民.数据结构(C语言版)[M].北京: 清华大学版社,2007 [2]严蔚敏,吴伟民,米宁.数据结构习题集(C语言版)[M].北京: 清华大学版社,2007 [3]谭浩强.C语言程序设计(第二版)学习指导.清华大学出版社,2000 [4]数据结构与算法分析,APracticalIntroductiontoDataStructuresandAlgorithmAnalysisJavaEditionCliffordA.Shaffer,张铭,刘晓丹译 电子工业出版社2001 [5]王淑礼,王新霞.算术表达式求值算法实现的难点剖析[J].福建电脑,2012 [6]唐蔼明,谢泉钦.算术表达式程序设计算法分析[J].闽江学院学报,2013 [7]殷人昆.数据结构(C++版)[M].北京: 清华大学版社,2001 致谢 在这次数据结构程序设计中,我得到了杨书鸿老师的认真指导和帮助,同时也感谢我的队友王毅宏同学,因为他才提高了我设计进度和效率。 我和王毅宏同学共同完成这次课程设计,在程序设计过程中难免会遇到各种问题,谢谢杨老师的耐心指导,谢谢同伴的包容,在这次课程设计中我感觉我有了很大的提高,我相信自己以后会做得更好。 通过本次设计,我的知识领域得到了进一步扩展,专业技能进一步提高,同时增强了分析和解决实际问题的综合能力。 首先,我们要感谢学校给我们提供了此次课程设计的机会,能让我们在一起学习与研究,让我们有机会对所学的理论知识进行实践。 最后,在我设计完成后对程序的测试,并在同学与队友的帮助下才得以完成没有他们,也许就难以发现一些潜在的错误,在此一并表示感谢 附录 源程序如下: #include #include #include #include #include #include typedefstruct{//哈夫曼树的结构体 charch; intweight;//权值 intparent,lchild,rchild; }htnode,*hfmtree; typedefchar**hfmcode; voidSelect(hfmtree&HT,inta,int*p1,int*p2)//Select函数,选出HT树到a为止,权值最小且parent为0的2个节点 { inti,j,x,y; for(j=1;j<=a;++j){ if(HT[j].parent==0){ x=j; break; } } for(i=j+1;i<=a;++i){ if(HT[i].weight x=i;//选出最小的节点 } } for(j=1;j<=a;++j){ if(HT[j].parent==0&&x! =j) { y=j; break; } } for(i=j+1;i<=a;++i) { if(HT[i].weight =i) { y=i;//选出次小的节点 } } if(x>y){ *p1=y; *p2=x; } else { *p1=x; *p2=y; } } voidhfmcoding(hfmtree&HT,hfmcode&HC,intn)//构建哈夫曼树HT,并求出n个字符的哈夫曼编码HC { inti,start,c,f,m,w; intp1,p2; char*cd,z; if(n<=1){ return; } m=2*n-1; HT=(hfmtree)malloc((m+1)*sizeof(htnode)); for(i=1;i<=n;++i)//初始化n个叶子结点 { printf("请输入第%d字符信息和权值: ",i); scanf("%c%d",&z,&w); while(getchar()! ='\n') { continue; } HT[i].ch=z; HT[i].weight=w; HT[i].parent=0; HT[i].lchild=0; HT[i].rchild=0; } for(;i<=m;++i)//初始化其余的结点 { HT[i].ch='0'; HT[i].weight=0; HT[i].parent=0; HT[i].lchild=0; HT[i].rchild=0; } for(i=n+1;i<=m;++i)//建立哈夫曼树 { Select(HT,i-1,&p1,&p2); HT[p1].parent=i;HT[p2].parent=i; HT[i].lchild=p1;HT[i].rchild=p2; HT[i].weight=HT[p1].weight+HT[p2].weight; } HC=(hfmcode)malloc((n+1)*sizeof(char*)); cd=(char*)malloc(n*sizeof(char)); cd[n-1]='\0'; for(i=1;i<=n;++i)//给n个字符编码 { start=n-1; for(c=i,f=HT[i].parent;f! =0;c=f,f=HT[f].parent) { if(HT[f].lchild==c) { cd[--start]='0'; } else { cd[--start]='1'; } } HC[i]=(char*)malloc((n-start)*sizeof(char)); strcpy(HC[i],&cd[start]); } free(cd); } intmain(){ charcode[100],h[100],hl[100]; intn,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 哈夫曼编 译码器