哈呼曼编译器设计说明书.docx
- 文档编号:8244739
- 上传时间:2023-01-30
- 格式:DOCX
- 页数:18
- 大小:159.84KB
哈呼曼编译器设计说明书.docx
《哈呼曼编译器设计说明书.docx》由会员分享,可在线阅读,更多相关《哈呼曼编译器设计说明书.docx(18页珍藏版)》请在冰豆网上搜索。
哈呼曼编译器设计说明书
*******************
实践教学
*******************
兰州理工大学
计算机与通信学院
2007年春季学期
算法与数据结构课程设计
题目:
哈夫曼编译码器设计
专业班级:
05计算机科学与技术3班
姓名:
徐玉霞
学号:
05240317
指导教师:
李睿
成绩:
_____________________
目录
摘要2
前言3
正文4
1.采用类c语言定义相关的数据类型4
2.各模块的伪码算法4
3.函数的调用关系图7
4.调试分析7
5.测试结果8
6.源程序(带注释)10
参考文献18
致谢19
附件Ⅰ部分源程序代码20
摘要
该设计是对输入的一串电文字符实现哈夫曼编码,再对哈夫曼编码生成的代码串进行译码,输出电文字符串。
在该设计中把数据压缩过程称为编码,解压缩的过程称为译码。
此程序中建立了哈夫曼树,并利用建好的哈夫曼树对文件中的正文进行编码,对文件中的代码进行译码,显示输出等功能。
关键词:
哈夫曼树,哈夫曼编码,哈夫曼译码。
前言
哈夫曼编码的应用很广泛,利用哈夫曼树求地的二进制编码称为哈夫曼编码。
哈夫曼树中从根到每个叶子都有一条路径,对路径上的各分支约定:
指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为对应的编码,这就是哈夫曼编码。
我们在对一些问题进行求解时,会发现有些问题很难找到规律,或者根本无规律可寻。
对于这样的问题,可以利用计算机运算速度快的特点,先搜索查找所有可能出现的情况,再根据题目条件从所有可能的情况中,删除那些不符合条件的解。
由哈夫曼算法的定义可知,初始森林中共有n棵只含有根结点的二叉树。
算法的的第二步是:
算法的的第二步是:
将当前森林中的两棵根结点权值最小的二叉树,合并成一棵新的二叉树,每合并一次,森林中就减少一棵树,产生一个新结点。
则要进行n-1次合并,所以共产生n-1个新结点。
由此可知,最终求得的哈夫曼树中一共有2n-1个结点。
其中,n个结点是初始森林中的n个孤立结点。
并且哈夫曼树中没有度数为1的分支的结点。
采用哈夫曼编码方案,即应用哈夫曼树构造使电文的编码总长最短的编码方案。
正文
1.采用类C语言定义相关的数据类型
(1)哈夫曼树的存储结构定义为:
typedefstruct/*字符集的元素结构*/
{chardata;
intweight;//权值
}elemtype;
typedefstruct/*哈夫曼树的元素结构*/
{chardata;
intflag;
intweight;//权值
intparent,lchild,rchild;//左右孩子及双亲指针
}htnode,*huffmantree;//动态分配数组存储哈夫曼树
typedefchar**HuffmanCode;//动态分配数组存储哈夫曼编码表
(2)哈夫曼树的存储结构描述:
#include
#include
#include
#definen27/*字符集的容量*/
#defineMAXVALUE1000/*权值的最大值*/
#defineMAXNODE35//哈夫曼树最多节点数
#defineMAXD100
2.各模块的伪码算法:
(1)构造哈夫曼树的算法
voidChuffmanTree(HuffmanTreeHT,HuffmancodeHc,intcnt[],charstr[])
{/*构造哈夫曼树HT,cnt中存放每类字符在电文中出项的频率,str中存放电文中不同类的字符*/
inti,s1,s2;
for(i=1;i<=2;*num-1;i++)
{
HT[i].lchild=0;HT[i].rchild=0;
HT[i].parent=0;HTweight=0;
}
for(i=1;i<=2*num;i++)/*输入num个结点的权值*/
HT[i].weight=cnt[i];
for(i=num+1;i<=2*num-1;i++)
{/*在HT[1..i-1]中选择parent为0且权值最小的两个结点*/
selext(Ht,i-1,s1,s2);
HT[s1].parent=i;HT[s2].parent=i;
Ht[i].lchild=s;HT[i].rchild=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,次数为:
%d\n",HC[i].ch,cnt[i++]);
}
(2)求哈夫曼编码(huffmancode)算法:
HuffmanCodehuffmancode(huffmantreeht)
{char*cd;
intc,i,f,start;
HuffmanCodeHC;
HC=(HuffmanCode)malloc((n+1)*sizeof(char*));//分配n个字符编码的头指针向量
cd=(char*)malloc(n*sizeof(char));//分配求编码的工作区间
cd[n-1]='\0';//编码结束符标志
for(i=1;i<=n;i++)//逐个字符求哈夫曼编码
{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';
elsecd[--start]='1';
HC[i]=(char*)malloc((n-start)*sizeof(char));//为第i个字符编码分配空间
strcpy(HC[i],&cd[start]);//从cd复制编码(串)到HC
}
for(i=1;i<=n;i++)
puts(HC[i]);
free(cd);//释放工作空间
return(HC);
}
(3)求测试数据的编码(encoding)算法:
voidencoding(huffmantreeht,char**hc)//根据哈夫曼树HT求哈夫曼编码表HC
{inti,j,k;
charsstring[MAXNODE];
clrscr();
flushall();
printf("inputhuffmancode\neg.:
thisisprogrammaismyfavorite:
\n");
gets(sstring);
for(i=0;i {for(j=1;j<=n;j++) if(sstring[i]==ht[j].data) {k=j; break; } (4)哈夫曼译码算法: voiddecoding(huffmantreeht)//代码文件的译码 {chara[MAXD]; intm,i; clrscr(); scanf("%s",a); m=2*n-1; for(i=0;a[i]! ='\0';i++) {if(a[i]=='0')m=ht[m].lchild; elsem=ht[m].rchild; if(m<=n) {printf("%c",ht[m].data); m=2*n-1; } } } 3.函数调用关系图: 4.调试分析: a.调试中遇到的问题及对问题的解决方法: 在对源程序进行调试时,当输入字符后,应正确判断所输入的字符是否满足程序的需求,且保正所输入字符后所输出语句功能唯一。 则在源程序中加入了一条while()判断语句,若while()判断语句中表达式成立,就重新获取一个字符,然后对while()语句进行重新判断,直到while()判断语句中表达式不成立,就执行switch()语句中于其输入字符相对应的case’’语句.其程序语句如下: while(ch! ='r'&&ch! ='c'&&ch! ='e'&&ch! ='d'&&ch! ='q') ch=getchar();/*选取功能*/ switch(ch) {case'r': readdata(w);break;/*初始化(readdata),读取数据*/ case'c': ht=createhuff(w);break;/*建立哈夫曼树(createhuff)*/ case'e': hc=huffmancode(ht);encoding(ht,hc);break; /*求字符集的哈夫曼编码(huffmancode)和求测试数据的编码(encoding)*/ case'd': decoding(ht);break;/*译码(decoding)*/ case'q': return;/*程序结束,返回*/ } b.算法的时间复杂度和空间复杂度 时间复杂度: 建立哈夫曼树: O(n³) 对文件中正文进行编码: O(n2) 对文件中的代码进行译码: O(n) 5测试结果 对下列给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的编码和译码: “THISPROGRAMISMYFAVORITE“。 字符空格ABCDEFGHIJKLM 频度1866413223210321154757153220 字符NOPQRSTUVWXYZ 频度5763151485180238181161 输入r后: 输入c后: 输入e后: 6.源程序(带注释) #include #include #include #definen27/*字符集的容量*/ #defineMAXVALUE1000/*权值的最大值*/ #defineMAXNODE35//哈夫曼树最多节点数 #defineMAXD100 typedefstruct/*字符集的元素结构*/ {chardata; intweight; }elemtype; typedefstruct/*哈夫曼树的元素结构*/ {chardata; intflag; intweight;//权值 intparent,lchild,rchild;//左右孩子及双亲节点 }htnode,*huffmantree;//动态分配数组存储哈夫曼树 typedefchar**HuffmanCode;//动态分配数组存储哈夫曼编码表 voidreaddata(elemtype*w); huffmantreecreatehuff(elemtype*w); char**huffmancode(huffmantreeht); voidencoding(huffmantreeht,char**hc); voiddecoding(huffmantreeht); //初始化readdata,读取数据 voidreaddata(elemtype*w) {inti; w[0].data='';w[0].weight=186; w[1].data='a';w[1].weight=64; w[2].data='b';w[2].weight=13; w[3].data='c';w[3].weight=22; w[4].data='d';w[4].weight=32; w[5].data='e';w[5].weight=103; w[6].data='f';w[6].weight=21; w[7].data='g';w[7].weight=15; w[8].data='h';w[8].weight=47; w[9].data='i';w[9].weight=57; w[10].data='j';w[10].weight=1; w[11].data='k';w[11].weight=5; w[12].data='l';w[12].weight=32; w[13].data='m';w[13].weight=20; w[14].data='n';w[14].weight=57; w[15].data='o';w[15].weight=63; w[16].data='p';w[16].weight=15; w[17].data='q';w[17].weight=1; w[18].data='r';w[18].weight=48; w[19].data='s';w[19].weight=51; w[20].data='t';w[20].weight=80; w[21].data='u';w[21].weight=23; w[22].data='v';w[22].weight=8; w[23].data='w';w[23].weight=18; w[24].data='x';w[24].weight=1; w[25].data='y';w[25].weight=16; w[26].data='z';w[26].weight=1; for(i=0;i<27;i++) {printf("%c",w[i].data); printf("%d\t",w[i].weight); } return; } huffmantreecreatehuff(elemtype*w) {inti,j,x1,x2; intm1,m2,m; huffmantreeHT,p; m=2*n-1; HT=(huffmantree)malloc((m+1)*sizeof(htnode));//0号单元未用 p=HT;p++; for(i=1;i<=m;i++,p++,w++)//初始化HT {if(i<=n) { p->data=w->data; p->weight=w->weight; } else { p->data='\0'; p->weight=0; } p->parent=0; p->lchild=0; p->rchild=0; p->flag=0; } for(i=1;i {m1=m2=MAXVALUE; x1=x2=0; p=HT; for(j=1;j<=n-1+i;j++) { if(p[j].weight {m2=m1; x2=x1; m1=p[j].weight; x1=j; } elseif(p[j].weight {m2=p[j].weight; x2=j; } } p[x1].parent=n+i; p[x2].parent=n+i; p[x1].flag=1; p[x2].flag=1; p[n+i].weight=p[x1].weight+p[x2].weight; p[n+i].lchild=x1; p[n+i].rchild=x2; } clrscr(); for(i=1;i<=m;i++) {printf("%d,%c,%d,%3d,%3d,%3d,%3d\n",i,p[i].data,p[i].flag,p[i].weight,p[i].parent,p[i].lchild,p[i].rchild); if(i%15==0){ getch(); clrscr();} } return(HT); } HuffmanCodehuffmancode(huffmantreeht) {char*cd; intc,i,f,start; HuffmanCodeHC; //从叶子到根逆向求哈夫曼编码 HC=(HuffmanCode)malloc((n+1)*sizeof(char*));//分配n个字符的头指针向量 cd=(char*)malloc(n*sizeof(char));//分配求编码的工作区间 cd[n-1]='\0';//编码结束符 for(i=1;i<=n;i++)//逐个字符求哈夫曼编码 {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'; elsecd[--start]='1'; HC[i]=(char*)malloc((n-start)*sizeof(char));//为第i个字符编码分配空间 strcpy(HC[i],&cd[start]);//从cd复制编码串到HC } for(i=1;i<=n;i++) puts(HC[i]); free(cd);//释放工作区间 return(HC); } voidencoding(huffmantreeht,char**hc) {inti,j,k; charsstring[MAXNODE]; clrscr(); flushall(); printf("inputhuffmancode\neg.: thisisprogrammaismyfavorite: \n"); gets(sstring); for(i=0;i {for(j=1;j<=n;j++) if(sstring[i]==ht[j].data) {k=j; break; } if(k<=0||k>MAXNODE) {printf("thereisn'tNO.%dchar\n",i); continue; } printf("%c\tweight=%3d\t%s\n",ht[k].data,ht[k].weight,hc[k]); } } voiddecoding(huffmantreeht) {chara[MAXD]; intm,i; clrscr(); scanf("%s",a); m=2*n-1; for(i=0;a[i]! ='\0';i++) {if(a[i]=='0')m=ht[m].lchild; elsem=ht[m].rchild; if(m<=n) {printf("%c",ht[m].data); m=2*n-1; } } } main() {elemtypew[n];/*字符和频度集合类型*/ charch; huffmantreeht;/*哈夫曼树类型*/ HuffmanCodehc;/*编码类型*/ ch=getchar(); while(ch! ='q')/*当键入’q’时程序运行结束*/ { while(ch! ='r'&&ch! ='c'&&ch! ='e'&&ch! ='d'&&ch! ='q') ch=getchar();/*选取功能*/ switch(ch) {case'r': readdata(w);break;/*初始化(readdata),读取数据*/ case'c': ht=createhuff(w);break;/*建立哈夫曼树(createhuff)*/ case'e': hc=huffmancode(ht);encoding(ht,hc);break; /*求字符集的哈夫曼编码(huffmancode)和求测试数据的编码(encoding)*/ case'd': decoding(ht);break;/*译码(decoding)*/ case'q': return;/*程序结束,返回*/ } ch=getchar(); } } 总结 在这三周的数据结构课程设计中,我的题目是: 哈夫曼编译码器设计,这三周课程设计中,通过该题目的设计过程,我加深了对树的数据结构以及二叉树的逻辑结构,存储结构的理解,对树的数据结构上基本运算的实现有所掌握,对课本中所学的各种数据结构进一步理解和掌握,学会了如何把学到的知识用于解决实际问题,锻炼了自己动手的能力。 一个人要完成所有的工作是非常困难和耗时的。 在以后的学习中我会更加注意自己各个方面的能力的协调发展。 在课程设计时我遇到了很多的问题,在老师的帮助,和对各种资料的查阅中,将问题解决,培养了我自主动手,独立研究的能力,为今后在学习工作中能更好的发展打下了坚实的基础。 三周的课程设计很短暂,但其间的内容是很充实的,在其中我学习到了很多平时书本中无法学到的东西,积累了经验,锻炼了自己分析问题,解决问题的能力,并学会了如何将所学的各课知识融会,组织,来配合学习,三周中我收益很大,学到很多。 参考文献 1.严蔚敏,陈文博编著.数据结构及应用算法教程,北京: 清华大学出版社,2001 2.苏仕华主编.数据结构自学辅导.北京: 清华大学出版社,2002 3.苏仕华主编.数据结构与算法解析.合肥: 中国科学技术大学生出版社,2004 4.谭浩强编著.C程序设计.北京: 清华大学出版社,1991 附件Ⅰ部分源程序代码 栈的应用——用栈来实行编译(左右括号配对) 算法: voidpush(stacknode*st,elemtypex)/*将元素x入栈*/ { if(st->top==m)/*判断栈ST是否已满*/ printf("thestackisoverflow! \n"); else { st->top=st->top+1; st->stack[st->top]=x; } } voidpop(stacknode*st)/*将栈的栈顶元素出栈*/ { st->top=st->top-1; } 源程序: #definem20 #defineelemtypechar typedefstruct/*栈类型的定义*/ { elemtyp
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 哈呼曼 编译器 设计 说明书