赫夫曼课程设计说明书.docx
- 文档编号:29584136
- 上传时间:2023-07-24
- 格式:DOCX
- 页数:23
- 大小:73.59KB
赫夫曼课程设计说明书.docx
《赫夫曼课程设计说明书.docx》由会员分享,可在线阅读,更多相关《赫夫曼课程设计说明书.docx(23页珍藏版)》请在冰豆网上搜索。
赫夫曼课程设计说明书
目录
前言1
正文1
1.1课程设计的教学目的和任务1
1.2课程设计的主要内容1
1.3课程设计报告的要求2
2.1.问题描述及基本要求2
2.2.算法思想2
2.3模块划分2
2.3.1构造赫夫曼树2
2.3.2赫夫曼编码(huffmancode)3
2.4.数据结构5
2.5.算法的时空分析5
2.6测试数据6
2.7.测试情况6
总结7
参考文献:
7
附录9
前言
赫夫曼编码(HuffmanCoding)是一种编码方式,赫夫曼编码是可变字长编码(VLC)的一种。
赫夫曼压缩是个无损的压缩算法,一般用来压缩文本和程序文件。
赫夫曼压缩属于可变代码长度算法一族。
意思是个体符号(例如,文本文件中的字符)用一个特定长度的位序列替代。
因此,在文件中出现频率高的符号,使用短的位序列,而那些很少出现的符号,则用较长的位序列。
赫夫曼编码的应用很广泛,利用赫夫曼树求地的二进制编码称为赫夫曼编码。
赫夫曼树中从根到每个叶子都有一条路径,对路径上的各分支约定:
指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为对应的编码,这就是赫夫曼编码。
我们在对一些问题进行求解时,会发现有些问题很难找到规律,或者根本无规律可寻。
对于这样的问题,可以利用计算机运算速度快的特点,先搜索查找所有可能出现的情况,再根据题目条件从所有可能的情况中,删除那些不符合条件的解。
由赫夫曼算法的定义可知,初始森林中共有n棵只含有根结点的二叉树。
算法的的第二步是:
算法的的第二步是:
将当前森林中的两棵根结点权值最小的二叉树,合并成一棵新的二叉树,每合并一次,森林中就减少一棵树,产生一个新结点。
则要进行n-1次合并,所以共产生n-1个新结点。
由此可知,最终求得的赫夫曼树中一共有2n-1个结点。
其中,n个结点是初始森林中的n个孤立结点。
并且赫夫曼树中没有度数为1的分支的结点。
采用赫夫曼编码方案,即应用赫夫曼树构造使电文的编码总长最短的编码方案。
正文
1.1课程设计的教学目的和任务
(1)使学生进一步理解和掌握所学的各种基本抽象数据类型的逻辑结构、存储结构和操作实现算法,以及它们在程序中的使用方法。
(2)使学生初步掌握软件开发过程的问题分析、设计、编码、测试等基本方法和基本技能。
(3)使学生掌握使用各种计算机资料和有关参考资料,提高学生进行程序设计的基本能力。
(4)使学生能用系统的观点和软件开发一般规范进行软件开发,培养软件工作者所应具备的科学的工作方法和作风。
1.2课程设计的主要内容
(1)问题分析和任务定义。
根据题目的要求,充分地分析和理解问题,明确问题要求做什么?
限制条件是什么?
(2)逻辑设计。
对问题描述中涉及的操作对象定义相应的数据类型,并按照以数据结构为中心的原则划分模块,定义主程序模块和各抽象数据类型。
逻辑设计的结果应写出每个抽象数据类型的定义(包括数据结构的描述和每个基本操作的功能说明),各个主要模块的算法,并画出模块之间的调用关系图。
(3)物理设计。
定义相应的存储结构并写出各函数的伪代码算法。
在这个过程中,要综合考虑系统功能,使得系统结构清晰、合理、简单和易于调试,抽象数据类型的实现尽可能做到数据封装,基本操作的规格说明尽可能明确具体。
详细设计的结果是对数据结构和基本操作作出进一步的求精,写出数据存储结构的类型定义,写出函数形式的算法框架。
(4)程序编码。
把详细设计的结果进一步求精为程序设计语言程序。
同时加入一些注解和断言,使程序中逻辑概念清楚。
(5)程序调试与测试。
采用自底向上,分模块进行,即先调试低层函数。
能够熟练掌握调试工具的各种功能,设计测试数据确定疑点,通过修改程序来证实它或绕过它。
调试正确后,认真整理源程序及其注释,形成格式和风格良好的源程序清单和结果。
(6)结果分析。
程序运行结果包括正确的输入及其输出结果和含有错误的输入及其输出结果。
算法的时间、空间复杂性分析。
(7)撰写课程设计报告。
1.3课程设计报告的要求
课程设计报告要求规范书写。
应当包括如下内容:
⑴问题描述:
描述要求编程解决的问题。
⑵基本要求:
给出程序要达到的具体的要求。
⑶测试数据:
设计测试数据,或具体给出测试数据。
要求测试数据能全面地测试所设计程序的功能。
⑷算法思想:
描述解决相应问题算法的设计思想。
⑸模块划分:
描述所设计程序的各个模块(即函数)功能。
⑹数据结构:
给出所使用的基本抽象数据类型,所定义的具体问题的数据类型,以及新定义的抽象数据类型。
⑺源程序:
给出所有源程序清单,要求程序有充分的注释语句,至少要注释每个函数参数的含义和函数返回值的含义。
⑻测试情况:
给出程序的测试情况,并分析运行结果。
⑼算法的时空分析(包括基本操作和其他算法的时间复杂度和空间复杂度的分析)和改进设想;经验和体会等。
⑽参考文献:
列出参考的相关资料和书籍。
2.1.问题描述及基本要求
利用赫夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本,试设计一个赫夫曼编码系统。
从键盘输入一段报文(如"whatdidyoudothatmadeyousohappy"),输出这段报文的赫夫曼编码。
2.2.算法思想
赫夫曼编码是根据可变长最佳编码定理,应用赫夫曼算法而产生的一种编码,是消除编码冗余度最常用的方法。
它的平均码字长度在具有相同输入概率集合的前提下,比其它任何一种可译码都小,因此,也常被称为紧凑码。
将输入的字符串统计其个数算出百分率,最为它的权值,然后将各权值创建赫夫曼树,计算出对应的编码。
通过译码字符串,从根部出发,按字符’0’和‘1’确定找左右孩子。
2.3模块划分
2.3.1构造赫夫曼树
给定n个实数w1,w2,......,wn(n≥2),求一个具有n个结点的二叉数,使其带权路径长度最小。
所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。
树的带权路径长度记为WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。
可以证明赫夫曼树的WPL是最小的。
(1)根据与n个权值{w1,w2…wn}对应的n个结点构成具有n棵二叉树的森林F={T1,T2…Tn},其中第i棵二叉树Ti(1≤i≤n)都只有一个权值为wi的根结点,其左、右子树均为空
(2)在森林F中选出两棵根结点的权值最小的树作为一棵新树的左、右子树,且置新树的根结点的权值为其左、右子树上根结点权值之和
(3)从F中删除构成新树的那两棵,同时把新树加入F中
(4)重复第
(2)和第(3)步,直到F中只含有一棵为止,此树便为赫夫曼树
voidCreatHFMTree(HFMTree*HT,intcount[]){//创建赫夫曼树
inti;
HFMTreep,HT1,HT2;//HT1,HT2分别存放权值最小和次小的节点的位置
p=*HT=(HFMTree)malloc(sizeof(HFMNode));
p->next=p->LChild=p->RChild=p->Parent=NULL;//初始化赫夫曼链表且有2n-1个节点
for(i=1;i<2*n-1;i++)
{p->next=(HFMTree)malloc(sizeof(HFMNode));
p=p->next;
p->next=p->LChild=p->RChild=p->Parent=NULL;
}
for(i=0,p=*HT;i p->weight=count[i]; p=p->next; } for(i=n;i<2*n-1;i++){//将后n-1个节点赋权值,建树 SelectMin(*HT,i,&HT1,&HT2);//每次从前i个节点中选取权值最小的两个节点 HT1->Parent=HT2->Parent=p; p->LChild=HT1; p->RChild=HT2; p->weight=HT1->weight+HT2->weight;//将两个节点的权值相加存入一个节点 p=p->next;//p指向下一个没有存储权值的节点 } } 2.3.2赫夫曼编码(huffmancode) 1根据最优二叉树构造赫夫曼编码,利用赫夫曼树很容易求出给定字符集及其概率(或频度)分布的最优前缀码。 赫夫曼编码正是一种应用广泛且非常有效的数据压缩技术。 该技术一般可将数据文件压缩掉20%至90%,其压缩效率取决于被压缩文件的特征。 (1)用字符s[i]作为叶子,count[i]做为叶子s[i]的权,构造一棵赫夫曼树,并将树中左分支和右分支分别标记为0和1; (2)将从根到叶子的路径上的标号依次相连,作为该叶子所表示字符的编码。 该编码即为最优前缀码(也称赫夫曼编码)。 代码如下: voidTotalCoding(chars[],CodeNodeHC[],charcode[]){ //利用赫夫曼编码表对整个字符串进行编码 inti,j;code[0]='\0';//编码数组初始化 for(i=0;s[i];i++) for(j=0;j if(s[i]==HC[j].ch) strcpy(code+strlen(code),HC[j].code+HC[j].start); } 2给定字符集的赫夫曼树生成后,求赫夫曼编码的具体实现过程是: 依次以叶子s[i](0≤i≤n-1)为出发点,向上回溯至根为止。 上溯时走左分支则生成代码0,走右分支则生成代码1。 (1)由于生成的编码与要求的编码反序,将生成的代码先从后往前依次存放在一个临时向量中,并设一个指针start指示编码在该向量中的起始位置. (2)当某字符编码完成时,从临时向量的start处将编码复制到该字符相应的位串中即可。 (3)因为字符集大小为n,故变长编码的长度不会超过n,加上一个结束符'\0'. 2.3.3建立赫夫曼表 voidHFMCode(HFMTreeHT,CodeNodeHC[],charstr[]){ //从每个叶子节点开始,利用赫夫曼树对每个字符进行编码,最终建立一个赫夫曼表 inti; HFMTreeq,p=HT; for(i=0;i HC[i].ch=str[i]; HC[i].code[n-1]='\0';//初始化编码的最后一位 } for(i=0;i HC[i].start=n-1; for(q=p;q->Parent;q=q->Parent)//判断q所指向的节点,左孩子置0,右孩子置1 if(q==q->Parent->LChild) HC[i].code[--HC[i].start]='0'; elseHC[i].code[--HC[i].start]='1'; p=p->next;//判断下一个叶子节点 } } 2.3.4赫夫曼译码算法 依次读人文件的二进制码,从赫夫曼树的根结点(即T[m-1])出发,若当前读人0,则走向左孩子,否则走向右孩子。 一旦到达某一叶子T时便译出相应的字符H.ch。 然后重新从根出发继续译码,直至文件结束。 代码如下: voidDeCoding(charcode[],HFMTreeHT,charstr[],chars[]){ //对赫夫曼编码进行解码,放入字符串s中 inti,j,k=0; HFMTreeroot,p,q; for(root=HT;root->Parent;root=root->Parent);//用root指向赫夫曼树的根结点 for(i=0,p=root;code[i];i++){//从根结点开始按编码顺序访问树 if(code[i]=='0') p=p->LChild; elsep=p->RChild; if(p->LChild==NULL&&p->RChild==NULL){ //到根节点时将该节点对应的字符输出 for(j=0,q=HT;q! =p;q=q->next,j++); s[k++]=str[j]; p=root;//回溯到根结点 } } s[k]='\0';//解码完毕,在字符串最后一个单元存入'\0' } 2.4.数据结构 主要定义了两个结构体 2.4.1定义赫夫曼树节点结构体 typedefstructnode{ intweight; structnode*LChild,*RChild,*Parent; //分别指向该节点的左孩子,右孩子,和双亲节点 structnode*next;//指向建立的赫夫曼树的下一个节点 }HFMNode,*HFMTree; 2.4.2定义赫夫曼编码的结构体 typedefstruct{ charch;//存储对应的字符 charcode[N+1];//存储对应字符的编码 intstart;//存储编码的起始位置 }CodeNode; 2.4.3各个函数间的关系如图: 图2.1各函数简的调用关系 2.5.算法的时空分析 时间复杂度: 构造赫夫曼树: T(n)=O(n) 建立赫夫曼表: T(n)=O(n2) 进行译码: T(n)=O(n) 赫夫曼编码T(n)=O(n³) 2.6测试数据 对下列给出的字符集数据建立赫夫曼树,并实现以下报文的编码和译码 字符串: "whatdidyoudothatmadeyousohappy" 字符空格ABCDEFGHIJKLM 频度1866413223210321154757153220 字符NOPQRSTUVWXYZ 频度5763151485180238181161 2.7.测试情况 2.7.1编码 首先在初始界面,选择编码,键盘中输入1如图2.2: 图1编译初始界面 图2编码界面 2.7.2通过编码出来的密码文件解码 最终的到的字符串,通过与原来的字符串对比,完全一样.说明编码解码成功。 总结 通过该题目的设计过程,对数据结构以及二叉树的逻辑结构,存储结构的理解,对树的数据结构上基本运算的实现有所掌握,对课本中所学的各种数据结构进一步理解和掌握,学会了如何把学到的知识用于解决实际问题,锻炼了自己动手的能力。 完成所有的工作是非常困难和耗时的。 在以后的学习中我会更加注意自己各个方面的能力的协调发展。 在课程设计时我遇到了很多的问题,在老师的帮助,和对各种资料的查阅中,将问题解决,培养了我自主动手,独立研究的能力,为今后在学习工作中能更好的发展打下了坚实的基础。 参考文献: [1]谭浩强编著.C++课程设计.北京: 清华大学社,2004 [2]S.B.Lippman,J.Lajoie著.潘爱民译.C++Primer(3rdEdition)中文版.北京: 中国电力出版社,2002 [3]H.M.Deitel,PaulJamesDeitel著.薛万鹏译.C++程序设计教程.北京: 机械工业出版社,2000 [4]StephenR.Savis著.C++ForDummies4thedition,IDGBooksWorldwide,Inc.,2002 [5]HarveyM.Deitel.JackW.Davidson著.邱仲潘译.C++大学教程(第二版).北京: 电子工业出版社,2002 [6]JamesP.Cohoon.JackW.Davidson著.刘瑞挺等译.C++程序设计(第三版).北京: 电子工业出版社 [7]Decoder编著.C/C++程序设计.北京: 中国铁道出版社,2002 [8]BrianOverland著.董梁等译.C++语言命令译解(第二版).北京: 机械工业出版社,2002 [9]H.M.Deitel,PaulJamesDeitel著.薛万鹏译.C/C++程序设计大全.北京: 机械工业出版社.1997 [10]AlStrevens,ClaytonWalnum著.林丽闽等译.标准C++宝典.北京: 电子工业出版社.2001 [11]MichaelJ.Young著.MasteringVisualC++6.0SybexInc.1999 [12]LeenAmmeraal著.刘瑞挺等译.C++程序设计教程(第三版).北京: zhongguo铁道出版社,2003 [13]吕凤翥著.C++语言程序设计.北方交通大学出版社,2003 [14]袁启昌著.C++语言程序设计.清华大学出版社,2004 [15]刘振安,刘燕君,孙忱C++语言课程设计.机械工业出版社,2007 [16]杨进才,沈显君,刘蓉编.C++语言程序设计教程.清华大学出版社,2006 [17]宋振会著.C++语言编程基础教程.清华大学出版社,2005 附录 #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,i,j,k,l; ifstreaminput_file;//文件输入输出流 ofstreamoutput_file; charchoice,str[100]; hfmtreeHT; hfmcodeHC; cout<<"\n"; cout<<""<<"计算机(3)班"<<""<<"Q07620307"<<""<<"XXX\n"; while(choice! ='Q'&&choice! ='q')//当choice的值不为q且不为Q时循环 { cout<<""<<"*************************赫夫曼编码/译码器*************************\n"; cout<<""<<"I.Init"<<""<<"E.Encoding"<<""<<"D.Decoding"<<""<<"Q.Exit\n"; cout<<"请输入您要操作的步骤: "; cin>>choice; if(choice=='I'||c
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 赫夫曼 课程设计 说明书