实用标准文档文案大全湖南科技学院数据结构课程设计报告课题:霍夫曼编码专业班级:信计1202学号:201205001239姓名:黄思琪指导教师:牛志毅11课程设计的目的和意义在当今信息爆炸时代,如何采用有效的数据压缩技术来节省数据文件的存储空间和计算机网络的传送时间已越来越引起人们的重视。哈夫曼编码正是一种应用广泛且非常有效的数据压缩技术。哈夫曼编码的应用很广泛,利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。树中从根到每个叶子都有一条路径,对路径上的各分支约定:指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为和各个对应的字符的编码,这就是哈夫曼编码。通常我们把数据压缩的过程称为编码,解压缩的过程称为解码。电报通信是传递文字的二进制码形式的字符串。但在信息传递时,总希望总长度尽可能最短,即采用最短码。22.需求分析课题:哈夫曼编码译码器系统问题描述:打开一篇英文文章,统计该文章中每个字符出现的次数,然后以它们作为权值,对每一个字符进行编码,编码完成后再对其编码进行译码。问题补充:1.从硬盘的一个文件里读出一段英语文章;2.统计这篇文章中的每个字符出现的次数;3.以字符出现字数作为权值,构建哈夫曼树4.对每个字符进行编码并将所编码写入文件然后对所编码进行破译。具体介绍:在本课题中,我们在硬盘D盘中预先建立一个xuzhimo.txt文档,在里面编辑一篇文章(大写)。然后运行程序,调用fileopen()函数读出该文章,显示在界面;再调用tongji()函数对该文章的字符种类进行统计,并对每个字符的出现次数进行统计,并且在界面上显示;然后以每个字符出现次数作为权值,调用Create_huffmanTree()函数构建哈夫曼树。然后调用Huffman_bianma()函数对哈夫曼树进行编码,调用coding()函数将编码写入文件。33系统(项目)设计(1)设计思路及方案本课题是用最优二叉树即哈夫曼树来实现哈夫曼编码译码器的功能。假设每种字符在电文中出现的次数为Wi,编码长度为Li,电文中有n种字符,则电文编码总长度为(W1*L1)+(W2*L2)+…+(Wi*Li)。若将此对应到二叉树上,Wi为叶结点,Li为根结点到叶结点的路径长度。那么,(W1*L1)+(W2*L2)+…+(Wi*Li)恰好为二叉树上带权路径长度。因此,设计电文总长最短的二进制前缀编码,就是以n种字符出现的频率作权,构造一棵哈夫曼树,此构造过程称为哈夫曼编码。该系统将实现以下几大功能:从硬盘读取字符串,建立哈夫曼树,输出哈夫曼树的存储结构的初态和终态,输出各种字符出现的次数以及哈夫曼编码的译码等。(2)模块的设计及介绍1从硬盘读取字符串fileopen(参数){实现命令;打印输出;}2建立HuffmanTree通过三个函数来实现:voidselect_min(参数){初始化;for{接受命令;4处理命令;}}说明:在ht[1....k]中选择parent为0且权值最小的两个根结点的算法inttongji(参数){初始化;for{接受命令;处理命令;}}说明:统计字符串中各种字母的个数以及字符的种类voidCreate_huffmanTree(){初始化;for{接受命令;处理命令;}输出字符统计情况;}说明:构造哈夫曼树3哈夫曼编码voidHuffman_bianma(参数){定义变量;5{处理命令;}}说明:哈夫曼编码(3)主要模块程序流程图下面介绍三个主要的程序模块流程图:①主函数流程图:图3.1结束统计字符种类及频率字符总数num建立哈夫曼树哈夫曼编码打开文件?开始否是6流程图注释:该图比较简单,主要是调用各个函数模块,首先代开已经存在的文件,然后统计总的字符数以及出现的各个字符和频率。然后才开始建立哈夫曼树,接着在哈夫曼树的基础上对其进行编码。最后输出结束。②构造哈夫曼树:图3.2流程图注释:开始结束第i个结点权值i=num?创建哈夫曼树输出字符统计情况第i个根结点i=2*num-1?i=num?否是否是否是7该图是表示构造哈夫曼树的过程。首先输入num个叶结点的权值,当i=num是循环结束。然后进行哈夫曼树的构建,当i=2*num-1是循环结束。最后输出所得到的字符统计情况。③哈夫曼编码:图3.3流程图解释:该流程图表四哈夫曼编码情况。首先初始化,Cd[--start]=0,start=num。然后进行编码,当cd[--start]=T[p].lchild==c时,cd[--start]=0;当结束开始T[p].left=c?i=num?Cd[--start]=0,start=numCd[--start]=0Cd[--start]=1否否是是8cd[--start]=T[p].left!==c时,cd[--start]=1。这个编码循环一直到i=num时结束。94系统实现各模块关键代码及算法的解释:①主调函数代码解释:这是main函数里的各个函数调用情况。fileopen(string);//从硬盘中读取文件num=tongji(string,cishu,str);//统计字符种类及各类字符出现的频率Create_huffmanTree(HT,HC,cishu,str);//建立哈夫曼树Huffman_bianma(HT,HC);//生成哈夫曼编码②建立HuffmanTree代码解释:该函数为在ht[1....k]中选择parent为0且权值最小的两个根结点的算法,其序号为s1和s2。voidselect_min(HuffmanTreeT,intk,int&x1,int&x2){inti,j;intmin1=1000;for(i=1;i=k;i++)if(T[i].weightmin1&&T[i].parent==0){j=i;min1=T[i].weight;}x1=j;min1=1000;for(i=1;i=k;i++)if(T[i].weightmin1&&T[i].parent==0&&i!=x1){j=i;min1=T[i].weight;10}x2=j;}代码解释:下面函数用来统计字符串中各种字母的个数以及字符的种类。当字符在A和Z之间时即被计数,并用str[j]保存字母到数组中,用cnt[j]统计每种字符个数。j返回总共读取的字符数目。inttongji(char*s,intcishu[],charstr[]){inti,j,k;char*p;intt[27];for(i=1;i=26;i++)t[i]=0;for(p=s;*p!='\0';p++){if(*p='A'&&*p='Z')k=*p-64;t[k]++;}for(i=1,j=0;i=26;++i)if(t[i]!=0){j++;str[j]=i+64;cishu[j]=t[i];returnj;}11代码解释:下面函数用来构造哈夫曼树HT。首先初始化哈夫曼树,然后输入前面统计的各结点的权值,用for循环来构造哈夫曼树。voidCreate_huffmanTree(HuffmanTreeht,HuffmanCodehc,intcishu[],charstr[]){//生成哈夫曼树HTinti,s1,s2;for(i=0;i2*num-1;i++){ht[i].left=0;ht[i].right=0;ht[i].parent=0;ht[i].weight=0;}for(i=1;i=num;i++)//输入num个叶结点的权值ht[i].weight=cishu[i];for(i=num+1;i=2*num-1;i++){//选择parent为0且权值最小的两个根结点,其序号为s1和s2,i为双亲select_min(ht,i-1,s1,s2);ht[s1].parent=i;ht[s2].parent=i;ht[i].left=s1;ht[i].right=s2;ht[i].weight=ht[s1].weight+ht[s2].weight;}for(i=0;i=num;i++)hc[i].ch=str[i];//字符的种类i=1;while(i=num)printf(字符%c次数:%8d\n,hc[i].ch,cishu[i++]);}12③生成Huffman编码并写入文件代码解释:根据哈夫曼树T求哈夫曼编码H。voidHuffman_bianma(HuffmanTreeT,HuffmanCodeH)//根据哈夫曼树T求哈夫曼编码H{intchild,parent,i;//child和parent分别指示t中孩子和双亲charcode[n];//存放编码intstart;//指示码在code中的起始位置code[num]='\0';//最后一位(第num个)放上串结束符for(i=1;i=num;++i){start=num;//初始位置child=i;//从叶子结点到根结点进行遍历while((parent=T[child].parent)0)//直至t[child]是树根为止{//若t[child]是t[parent]的左孩子,则生成0;否则生成1if(T[parent].left==child)code[--start]='0';elsecode[--start]='1';child=parent;}strcpy(H[i].co,&code[start]);H[i].len=num-start;}}13代码解释:对str所代表的字符串进行编码并写入文件。将翻译的二进制码写入文本文件。voidcoding(HuffmanCodehc,char*str){//对str所代表的字符串进行编码并写入文件inti,j;FILE*fp;fp=fopen(codefile.txt,w);while(*str){for(i=1;i=num;i++)if(hc[i].ch==*str){for(j=0;j=hc[i].len;j++)fputc(hc[i].co[j],fp);break;}str++;}fclose(fp);}145系统调试本次测试是在我的电脑的D盘中建立一个名为file.txt的文本文档,其中有大写字母IAMASTUDENT,期望程序能将其读出至界面并实现其他相关的功能。运行程序后,我们可以见到一下的运行界面。从硬盘中读出已有的文本文件输出所读字符的种类和每种字符的个数输出编码15小结通过一周的课程设计使我对哈夫曼树以及哈夫曼编码有了更深的认识和理解,也使我更加明白哈夫曼编码译码在信息技术中的重要性和地位。首先我谈谈我在设计期间我遇到的难点。开始的时候,代码中有许多的错误,特别是有一个“无法找到文件”的错误让我束手无策,最后还是屏蔽了定义的四个头文件然后慢慢地改正错误才让我又看到了希望。然后在实现文章的读入时,由于对文件不是太熟悉,只好翻开C语言书本仿照其模式编写,但后来进入了死循环,最后的解决方式是把main函数里的一个do…while循环去掉。许多的错误让我明白了一个道理---细心是非常重要的。同时,对于编程者而言,思路清晰是相当重要的。在适当的时候和同学一起交流探讨是一个十分好的学习机会。这次课程设计不但让我学得了一些编程知识,还学会了系统的做一份课程设计报告,学会了如何截图,学会了如何更好的画流程图,明白了做事情只有认真,才能真正做得更好!通过这次课程设计,我看清楚了自己的编程功底和动手能力还很不足,这主要是平时实践太少的缘故。我想,在未来的暑假中,我会努力尝试编写一些程序。在这个程序中,还有许多地方值得完善。比如,读出文本只能是大写的文档,空格和小写不能识别。由于时间问题,暂时不能实现了,我想在暑假里好好研究这个问题。未完成:哈夫曼译码1617附录源程序#includestdio.h#includestring.h#includestdlib.h#includefstream.h//类型相关变量的定义#definen100#definem