1、霍夫曼编译器课设沈阳航空航天大学课 程 设 计 报 告课程设计名称:数据结构课程设计课程设计题目:霍夫曼编/译码器院(系):专 业:班 级: 学 号: 姓 名: 指导教师: 目 录1 需求分析 11.1 问题描述 11.2 问题理解 12 系统设计 22.1 总体方案设计 22.2 数据结构设计 22.3 函数设计 32.4 关键流程 42.4.1 系统主流程 42.4.3 创建霍夫曼树函数流程函数 72.4.4 霍夫曼树建立霍夫曼表的函数流程 83 调试分析 104 测试及运行结果 11参考文献 13附 录 14 1 需求分析1.1 问题描述设计一个利用霍夫曼算法的编码与译码系统,可以接收来
2、自键盘输入的字符集大小、字符和权值信息,创建霍夫曼树生成霍夫曼编码并能对其进行译码的系统。1.2 问题理解首先,建立的霍夫曼编码与译码器并能够接受字符集大小、字符和权值信息,因此用字符数组存储字符串,把相同字符出现的次数作为每个字符的权值,用数组存储,建立一个链表,依次存储字符串中的字符,建立霍夫曼树,选取两个权值最小的字符组合,依次构成霍夫曼树,以左孩子码为0,右孩子为1,对霍夫曼树中的节点进行编码以及译码的应用。2 系统设计2.1 总体方案设计打开存放字符或编码的文件,将文件中的字符串存入字符串数组里,查找字符串中字符的个数和每个字符出现的次数,创建霍夫曼树,将各个字符出现的次数作为权值,
3、存入霍夫曼链表的前n个单元中,将后n-1个节点赋权值,建树,从每个叶子节点开始,利用霍夫曼树对每个字符进行编码,最终建立一个霍夫曼表,利用霍夫曼编码表对整个字符串进行编码,对霍夫曼编码进行解码,放入字符串s中。2.2 数据结构设计本程序的数据结构设计用了霍夫曼树的节点结构体,编码结构体其结构体如下:typedef struct node int weight;struct node *LChild,*RChild,*Parent; struct node *next; HFMNode,*HFMTree;typedef struct char ch; char codeN+1; int star
4、t; CodeNode; 2.3 函数设计1本系统所设计的函数见表2.1。表2.1 函数列表函数名称函数原型功能描述mainvoid main()进入编码程序TransCodeTransCode(char code,char str,char ss,HFMTree *HT,CodeNode HC)对经过编码得到的字符串码进行解码CodingCoding(char s,char str,char code,int count,HFMTree *HT,CodeNode HC)对文件中的字符串进行编码DeCodingDeCoding(char code,HFMTree HT,char str,cha
5、r s)将编码进行解码存入字符串数组ss中TotalCodingTotalCoding(char s,CodeNode HC,char code)利用哈夫曼编码表对整个字符串进行编码HFMCodeHFMCode(HFMTree HT,CodeNode HC,char str)/从每个叶子节点开始,利用哈夫曼树对每个字符进行编码,最终建立一个哈夫曼表CreatHFMTreeCreatHFMTree(HFMTree *HT,int count)创建哈夫曼树SelectMinSelectMin(HFMTree HT,int k,HFMTree *HT1,HFMTree *HT2)查找哈夫曼链表中两个
6、权值最小的节点SearchStrSearchStr(char s,char str,int count)查找字符串中字符的个数和每个字符出现的次数SaveSave(char s)保存字符或编码到文件中OpenOpen(char s)打开存放字符或编码的文件,将其存入字符串数组中2本系统函数的调用关系见图2.1。图2.1 函数调用关系2.4 关键流程2.4.1 系统主流程(1)主函数的简单描述:首先主函数调用清屏函数Clearscreen(),然后,当choice=1,调用函数Coding(s,str,code,count,&HT,HC),实现对文件中的字符串进行编码功能;当choice=2,调
7、用函数TransCode(code,str,ss,&HT,HC),实现对经过编码得到的字符串码进行解码功能;当choice!=0,主函数进行循环;当choice=0,主函数调用结束。(2)主函数的流程图本函数的具体流程见图2.2。sM和ssM是两个字符数组;Clearscreen()是清屏函数;choice则是switch语句;Coding是对文件中的字符串进行编码;TransCode是对经过编码得到的字符串码进行解码。图2.2 主函数的流程图2.4.2 打开存放字符文件,存入字符串数组流程(1)打开存放字符文件,存入字符串数组流程的简单描述:本函数的功能是:首先判断文件是否为空,然后将文件中
8、的字符存到数组中,当数组中的元素不为EOF时就进行循环直到不满足循环条件结束。(2)打开存放字符文件,存入字符串数组流程流程图。本函数的具体流程见图2.3。fp是一个文件;si存储文件中字符fget(fp)。图2.3 打开存放字符文件,存入字符串数组流程图2.4.3 创建霍夫曼树函数流程函数(1)霍夫曼树函数的简单描述:写出本函数的具体功能为:当满足iweight是权值;count起计数作用;SelectMin查找字符串中字符的个数和每个字符出现的次数。图2.4霍夫曼树函数的流程图2.4.4 霍夫曼树建立霍夫曼表的函数流程(1)霍夫曼树对每个字符进行编码,最终建立一个霍夫曼表的函数简单描述:本
9、函数的功能是:首先将字符存入哈夫曼编码结构体数组的字符单元中,然后将叶子结点的数值转换到创建的霍夫曼表中。(2)霍夫曼树建立霍夫曼表的函数流程图本函数的具体流程见图2.5。HC是CodeNode结构体数组, str是字符型数组;q-Parent不为空的作用是判断q所指向的节点,左孩子置0,右孩子置1 q=q-Parent-LChild是将p指向p的左孩子;p=p-next是将将p指向p的下一个结构体。图2.5霍夫曼树建立霍夫曼表的函数流程图3 调试分析 (1) 问题1 问题描述:编码过程中字符串编码总是缺少很多位,甚至不能编码一些字符。 问题分析:字符串编码总是缺少很多位,说明导致这种情况的可
10、能是节点不够多,致使编码没空间存储。 解决方法:初始化霍夫曼链表的节点不够,如果假设字符串有n个,那链表节点至少得有2n-1个,比如对4个字符串编码,先在4个字符里选2个权值最小的字符,2个字符权值相加,生成新的一个节点存储,现在还剩3个节点,同理3选2,生成新节点,剩余一个节点最后与上一步生成的节点配对,因此共需要生成3个新节点来存储。(2) 问题2 问题描述: 程序运行中,当创建树时,无法将树的元素存入到其中。 问题分析:无法存入其中,可能有两方面原因,第一:没有初始化树,即没有申请空间;第二方面:可能是 树的结构体定义出现错误。 解决方法: 在树的创建中,首先对其进行初始化,申请存储空间
11、,然后再输入树的元素,经过调试,结果正确。4 测试及运行结果(1)编码的具体的测试结果如图4.1所示。图4.1编码的测试结果(2)编码和保存编码的具体的测试结果如图4.2所示。图4.2 编码和保存编码的测试结果(3)译码和保存译码的具体的测试结果如图4.3所示。图4.3译码和保存译码的测试结果 参考文献1 严蔚敏,吴伟民.数据结构(C语言版)M.北京:清华大学出版社,20072 吕国英. 算法设计与分析M.北京:清华大学出版社,20063 徐宝文,李志.C程序设计语言M.北京:机械工业出版社,20044 Erich Gamma,Richard Helm.设计模式(英文版)M.北京:机械工业出版
12、社,2004附 录源程序清单:#include #include #include #define M 10000 #define N 128 typedef struct node int weight;struct node *LChild,*RChild,*Parent; struct node *next; /指向建立的哈夫曼树的下一个节点 HFMNode,*HFMTree;typedef struct char ch; char codeN+1; int start; CodeNode; int n; void clearscreen()system(cls);void Save(c
13、har s) char name10;FILE *fp;printf(请输入要保存的文件名:);gets(name);if(fp=fopen(name,wt)=NULL) printf(存储失败!); exit(1); fputs(s,fp);printf(n保存成功,文件名为:%s。n,name);printf(n按回车键继续.);getchar();fclose(fp);void Open(char s) char name10;FILE *fp;int i=0;printf(请输入要打开的文件名:);gets(name); if(fp=fopen(name,rt)=NULL) print
14、f(打开失败!n); exit(1); si+=fgetc(fp);while(si-1!=EOF) si+=fgetc(fp);si=0; fclose(fp);void SearchStr(char s,char str,int count)int i,j,k=0;for(i=0;iN;i+) counti=0;for(i=0;si;i+) for(j=0;jk;j+) if(strj=si) countj+; break; if(j=k) strk=si; countk+; strk=0; n=k-1; /将实际的字符个数作为叶子节点个数存入nvoid SelectMin(HFMTree
15、 HT,int k,HFMTree *HT1,HFMTree *HT2)int i,min;HFMTree p;min=32767;for(i=0,p=HT;inext) if(p-weightParent=0) min=p-weight; *HT1=p; min=32767;for(i=0,p=HT;inext) if(p-weightParent=0&p!=*HT1) min=p-weight; *HT2=p; void CreatHFMTree(HFMTree *HT,int count)int i;HFMTree p,HT1,HT2; p=*HT=(HFMTree)malloc(siz
16、eof(HFMNode);p-next=p-LChild=p-RChild=p-Parent=NULL; for(i=1;inext=(HFMTree)malloc(sizeof(HFMNode); p=p-next; p-next=p-LChild=p-RChild=p-Parent=NULL; for(i=0,p=*HT;iweight=counti; p=p-next; for(i=n;iParent=HT2-Parent=p; p-LChild=HT1; p-RChild=HT2; p-weight=HT1-weight+HT2-weight; p=p-next; void HFMCo
17、de(HFMTree HT,CodeNode HC,char str)int i;int j;HFMTree q,p=HT;for(i=0;in;i+) HCi.ch=stri; HCi.coden-1=0; for(i=0;iParent;q=q-Parent) if(q=q-Parent-LChild) HCi.code-HCi.start=0; else HCi.code-HCi.start=1; p=p-next; void TotalCoding(char s,CodeNode HC,char code)int i,j;code0=0; for(i=0;si;i+) for(j=0;
18、jParent;root=root-Parent); for(i=0,p=root;codei;i+) if(codei=0) p=p-LChild; else p=p-RChild; if(p-LChild=NULL&p-RChild=NULL) for(j=0,q=HT;q!=p;q=q-next,j+); sk+=strj; p=root; sk=0; void Coding(char s,char str,char code,int count,HFMTree *HT,CodeNode HC)clearscreen();printf(n打开存放字符串的文件.nn);Open(s); S
19、earchStr(s,str,count); CreatHFMTree(HT,count); HFMCode(*HT,HC,str); TotalCoding(s,HC,code); printf(n读入的字符串为:n);puts(s);printf(n最终的哈夫曼编码是:n);puts(code);printf(n保存编码,);Save(code); void TransCode(char code,char str,char ss,HFMTree *HT,CodeNode HC)clearscreen();printf(n打开编码的文件.nn);Open(code); DeCoding(c
20、ode,*HT,str,ss); printf(n最终得到的字符串为:n);puts(ss);printf(n保存译码,);Save(ss); main() char sM,ssM; char strN; int countN; char codeM; char choice;HFMTree HT; CodeNode HCN; do clearscreen(); printf(nn); printf( *哈夫曼树*n); printf( * *n); printf( * 1.编码。 *n); printf( * 2.译码。 *n); printf( * 0.退出。 *n); printf( *
21、 *n); printf( * *n); printf( * *n); printf( * 请输入相应操作的序号(0-2) *n); printf( *n); scanf(%c,&choice); getchar(); switch(choice) case 1: Coding(s,str,code,count,&HT,HC);break; case 2: TransCode(code,str,ss,&HT,HC);break; case 0: break; default : printf( 输入错误!请输入正确信息!n); while(choice!=0);课程设计总结:通过这次的课程设计
22、,深了我对程序的理解,特别是对一个大程序,来怎样进行对他组织及编写,数据结构这学期已经学完了。到了这最后的阶段,有了这样一个课程设计,感觉是挺好的,能够加强对一个大程序的宏观概念,使我更深刻的了解到学好数据结构这门课的重要性。在学习数据结构课程时,链表与树是我学习的难点与课程的重点,通过这次的课程设计,使我更清楚的明白链表与树深刻的含义,更加熟悉树的创建与链表的遍历并充分掌握其相关的内容。这个程序是通过调用多个子函数来把它实现,通过运用双亲孩子法创建霍夫曼树,建立霍夫曼树编码表来进行对一串字符串编码与译码。在整个课程设计的过程中,我慢慢了解到计算机科学与技术专业要求我们要有旺盛的求知欲,我们平时所学的是理论基础,但是对于计算机专业的人来说,光有理论是不够的,必须具备实践能力,通过这次课程设计使我们增强了实践能力,并能够与理论知识相结合,对今后的学习与这方面的发展奠定了基础。总的来说,这次的课程设计,充分锻炼了自己的动手能力及学到一些课程内其他没有学到过的知识,感觉获益良多! 感谢老师的耐心指导与帮助,在您的耐心指导下使我对课设的实践更得心应手了!下总之,课程设计是对我们学习的一种检验与提高,具有一定的挑战性,我期望我的未来充满这种挑战。指导教师评语:指导教师(签字): 年 月 日课程设计成绩
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1