哈夫曼编译码.docx
- 文档编号:12481385
- 上传时间:2023-04-19
- 格式:DOCX
- 页数:24
- 大小:427.02KB
哈夫曼编译码.docx
《哈夫曼编译码.docx》由会员分享,可在线阅读,更多相关《哈夫曼编译码.docx(24页珍藏版)》请在冰豆网上搜索。
哈夫曼编译码
数据结构课程设计
(2013-2014学年第一学期)
题目:
哈夫曼编码-译码
院系:
专业:
学生姓名:
学号:
指导教师:
年月日
1课程设计任务和要求………………………………………………1
2概要设计……………………………………………………………1
3详细设计……………………………………………………………2
4调试结果……………………………………………………………32
5课程设计总结………………………………………………………33
6附源程序清单………………………………………………………34
一、课程设计的任务和要求
[问题描述]
打开一篇英文文章,统计该文章中每个字符出现的次数,然后以它们作为权值,对每一个字符进行编码,编码完成后再对其编码进行译码。
[基本要求]
利用哈夫曼编码进行信息通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。
对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。
试为这样的信息收发站写一个哈夫曼编/译码系统。
[测试数据]
新建一个.txt文件,用来存放待处理的数据,这些数据为ASCII码值的集合,而且每种字符的数量并不能相同。
本实验拟设其中的数据为abbcccdddd.
二、概要设计
1.总体设计
一个完整的系统应具有以下功能:
(1)I:
初始化(Initialization)。
从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
(2)E:
编码(Encoding)。
利用已建好的哈夫曼树(如不在内存,则从文件htmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
(3)D:
译码(Decoding)。
利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
(4)P:
印代码文件(Print)。
将文件CodeFile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码写入文件CodePrint中。
(5)T:
印哈夫曼树(TreePrinting)。
将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
2.函数划分:
该程序有一个主函数和多个子函数,主函数完成对子函数的调用,各子函数实现相应的功能。
可以定义相应的抽象数据类型。
三、详细设计
1.算法
voidCrtHuffmanTree(HuffmanTree*ht,int*w,ElemTypes*d,intn)
{/*w存放已知的n个权值,构造哈夫曼树ht*/
intm,i;
ints1,s2;
m=2*n-1;
*ht=(HuffmanTree)malloc((m+1)*sizeof(HTNode));/*0号单元未使用*/
for(i=1;i<=n;i++)
{/*1-n号放叶子结点,初始化*/
(*ht)[i].weight=w[i];
(*ht)[i].data=d[i];
(*ht)[i].LChild=0;
(*ht)[i].parent=0;
(*ht)[i].RChild=0;
}
for(i=n+1;i<=m;i++)
{
(*ht)[i].weight=0;
(*ht)[i].LChild=0;
(*ht)[i].parent=0;
(*ht)[i].RChild=0;
}/*非叶子结点初始化*/
/*------------初始化完毕!
对应算法步骤1---------*/
for(i=n+1;i<=m;i++)/*创建非叶子结点,建哈夫曼树*/
{/*在(*ht)[1]~(*ht)[i-1]的范围内选择两个parent为0且weight最小的结点,其序号分别赋值给s1、s2返回*/
select(ht,i-1,&s1,&s2);
(*ht)[i].data=NULL;
(*ht)[s1].parent=i;
(*ht)[s2].parent=i;
(*ht)[i].LChild=s1;
(*ht)[i].RChild=s2;
(*ht)[i].weight=(*ht)[s1].weight+(*ht)[s2].weight;
}
}
voidPrint_d(HuffmanTree*HT,intm,charch,intn,FILE*fp,FILE*fps){//译码,递归调用
charc;
if(!
feof(fp)){//当文件CodeFile未结束
if(ch=='1'){
if((*HT)[(*HT)[m].RChild].RChild==0){//当到达叶子节点时
printf("%c",(*HT)[(*HT)[m].RChild].data);//输出翻译后的字符
fprintf(fps,"%c",(*HT)[(*HT)[m].RChild].data);
intm=2*n-1;
c=fgetc(fp);
Print_d(HT,m,c,n,fp,fps);
}
else{//未到达叶子结点时,继续从文件CodeFile读入01代码
c=fgetc(fp);
Print_d(HT,(*HT)[m].RChild,c,n,fp,fps);
}
}
if(ch=='0'){
if((*HT)[(*HT)[m].LChild].LChild==0){//当到达叶子节点时
printf("%c",(*HT)[(*HT)[m].LChild].data);
fprintf(fps,"%c",(*HT)[(*HT)[m].LChild].data);
intm=2*n-1;
c=fgetc(fp);
Print_d(HT,m,c,n,fp,fps);
}
else{
c=fgetc(fp);
Print_d(HT,(*HT)[m].LChild,c,n,fp,fps);
}
}
}
}
voidPrintTree(HuffmanTreeHT,intm,intnLayer)/*按竖向树状打印的二叉树*/
{
if(m!
=0){
if(HT==NULL)
return;
PrintTree(HT,HT[m].RChild,nLayer+1);
for(inti=0;i printf("-"); printf("%d\n",HT[m].weight); PrintTree(HT,HT[m].LChild,nLayer+1); } } 2.主要函数的实现 CrtHuffmanTree(&HT,w,d,n);//构建哈夫曼树。 CrtHuffmanCode(&HT,&HC,n,flag);//对哈夫曼树编码 CrtHuffmanCode(&HT,&HC,n,flag);//对文件编码 Print_d(&HT,m,ch,n,fp,fps);//译码 PrintTree(HT,m,nLayer);//打印 四、调试结果 五、课程设计总结 1、遇难到哪些问题,解决的方法。 一些算法的构成不理解,并且不会自己编写,对哈夫曼译码的算法不会等 2、通过本次课程设计,自己得到了哪些方面的训练和提高(经验和教训)。 多看书,多上网查资料,多向老师同学请教等,重视基本知识的运用,结合实际等 六、附源程序清单 #include #include #include #defineElemTypeschar typedefchar*HuffmanCode;/*动态分配数组,存储哈夫曼编码*/ typedefstruct { ElemTypesdata; unsignedintweight;/*用来存放各个结点的权值*/ unsignedintparent,LChild,RChild;/*指向双亲、孩子结点的指针*/ }HTNode,*HuffmanTree;/*动态分配数组,存储哈夫曼树*/ voidselect(HuffmanTree*ht,intn,int*s1,int*s2) { inti; intmin; for(i=1;i<=n;i++) { if((*ht)[i].parent==0) { min=i; i=n+1; } } for(i=1;i<=n;i++) { if((*ht)[i].parent==0) { if((*ht)[i].weight<(*ht)[min].weight) min=i; } } *s1=min; for(i=1;i<=n;i++) { if((*ht)[i].parent==0&&i! =(*s1)) { min=i; i=n+1; } } for(i=1;i<=n;i++) { if((*ht)[i].parent==0&&i! =(*s1)) { if((*ht)[i].weight<(*ht)[min].weight) min=i; } } *s2=min; } voidCrtHuffmanTree(HuffmanTree*ht,int*w,ElemTypes*d,intn) {/*w存放已知的n个权值,构造哈夫曼树ht*/ intm,i; ints1,s2; m=2*n-1; *ht=(HuffmanTree)malloc((m+1)*sizeof(HTNode));/*0号单元未使用*/ for(i=1;i<=n;i++) {/*1-n号放叶子结点,初始化*/ (*ht)[i].weight=w[i]; (*ht)[i].data=d[i]; (*ht)[i].LChild=0; (*ht)[i].parent=0; (*ht)[i].RChild=0; } for(i=n+1;i<=m;i++) { (*ht)[i].weight=0; (*ht)[i].LChild=0; (*ht)[i].parent=0; (*ht)[i].RChild=0; }/*非叶子结点初始化*/ /*------------初始化完毕! 对应算法步骤1---------*/ for(i=n+1;i<=m;i++)/*创建非叶子结点,建哈夫曼树*/ {/*在(*ht)[1]~(*ht)[i-1]的范围内选择两个parent为0且weight最小的结点,其序号分别赋值给s1、s2返回*/ select(ht,i-1,&s1,&s2); (*ht)[i].data=NULL; (*ht)[s1].parent=i; (*ht)[s2].parent=i; (*ht)[i].LChild=s1; (*ht)[i].RChild=s2; (*ht)[i].weight=(*ht)[s1].weight+(*ht)[s2].weight; } } voidCrtHuffmanCode(HuffmanTree*ht,HuffmanCode*hc,intn,intflag) /*从叶子结点到根,逆向求每个叶子结点对应的哈夫曼编码*/ { char*cd; inti; unsignedintc; intstart; intp; hc=(HuffmanCode*)malloc((n+1)*sizeof(char*));/*分配n个编码的头指针*/ cd=(char*)malloc(n*sizeof(char));/*分配求当前编码的工作空间*/ cd[n-1]='\0';/*从右向左逐位存放编码,首先存放编码结束符*/ for(i=1;i<=n;i++)/*求n个叶子结点对应的哈夫曼编码*/ { start=n-1;/*初始化编码起始指针*/ for(c=i,p=(*ht)[i].parent;p! =0;c=p,p=(*ht)[p].parent)/*从叶子到根结点求编码*/ if((*ht)[p].LChild==c) cd[--start]='0';/*左分支标0*/ else cd[--start]='1';/*右分支标1*/ hc[i]=(char*)malloc((n-start)*sizeof(char));/*为第i个编码分配空间*/ strcpy(hc[i],&cd[start]); } free(cd); if(flag==2){ FILE*fp1; if((fp1=fopen("e: \\hfmTree.txt","w"))==NULL){//创建文件hfmTree存储字符形式的编码 printf("Fileopenerror! \n"); exit(0); } printf("\n将下面的哈夫曼树写入文件hfmTree.txt中.\n"); fprintf(fp1,"字符\t权值\t编码\n"); printf("字符\t权值\t编码\n"); for(i=1;i<=n;i++){ printf("%c\t%d\t%s\n",(*ht)[i].data,(*ht)[i].weight,hc[i]); fprintf(fp1,"%c\t%d\t%s\n",(*ht)[i].data,(*ht)[i].weight,hc[i]);//写入文件hfmTree中 } printf("\n成功写入! \n"); if(fclose(fp1)){//关闭文件 printf("Cannotclosethefile! \n"); exit(0); } } if(flag==1){//当flag==1时对文件ToBeTran编码 FILE*fp; FILE*fps; charch; inti; if((fp=fopen("e: \\ToBeTran.txt","r"))==NULL){//从文件ToBeTran中读取要编码的文章。 printf("Fileopenerror! \n"); exit(0); } if((fps=fopen("e: \\CodeFile.txt","w"))==NULL){//创建文件CodeFile存储文件ToBeTran的编码 printf("Fileopenerror! \n"); exit(0); } printf("\n对文件ToBeTran.txt的文章进行编码: \n"); while(! feof(fp)){ ch=fgetc(fp); for(i=1;i<=n;i++){ if(ch! ='\0'){ if(ch==(*ht)[i].data){ fprintf(fps,"%s",hc[i]); printf("%s",hc[i]); } } } } printf("\n代码成功保存到文件CodeFile.txx中.\n\n"); if(fclose(fp)){//关闭文件 printf("Cannotclosethefile! \n"); exit(0); } if(fclose(fps)){//关闭文件 printf("Cannotclosethefile! \n"); exit(0); } } } voidPrint_d(HuffmanTree*HT,intm,charch,intn,FILE*fp,FILE*fps){//译码,递归调用 charc; if(! feof(fp)){//当文件CodeFile未结束 if(ch=='1'){ if((*HT)[(*HT)[m].RChild].RChild==0){//当到达叶子节点时 printf("%c",(*HT)[(*HT)[m].RChild].data);//输出翻译后的字符 fprintf(fps,"%c",(*HT)[(*HT)[m].RChild].data); intm=2*n-1; c=fgetc(fp); Print_d(HT,m,c,n,fp,fps); } else{//未到达叶子结点时,继续从文件CodeFile读入01代码 c=fgetc(fp); Print_d(HT,(*HT)[m].RChild,c,n,fp,fps); } } if(ch=='0'){ if((*HT)[(*HT)[m].LChild].LChild==0){//当到达叶子节点时 printf("%c",(*HT)[(*HT)[m].LChild].data); fprintf(fps,"%c",(*HT)[(*HT)[m].LChild].data); intm=2*n-1; c=fgetc(fp); Print_d(HT,m,c,n,fp,fps); } else{ c=fgetc(fp); Print_d(HT,(*HT)[m].LChild,c,n,fp,fps); } } } } voidPrintTree(HuffmanTreeHT,intm,intnLayer)/*按竖向树状打印的二叉树*/ { if(m! =0){ if(HT==NULL) return; PrintTree(HT,HT[m].RChild,nLayer+1); for(inti=0;i printf("-"); printf("%d\n",HT[m].weight); PrintTree(HT,HT[m].LChild,nLayer+1); } } voidTreePrint(HuffmanTree*ht,intm){ FILE*fp; inti; if((fp=fopen("e: \\TreePrint.txt","w"))==NULL){//同时将此字符形式的哈夫曼树写入文件TreePrint中 printf("Fileopenerror! \n"); exit(0); } printf("将字符形式的哈夫曼树存储到文件TreePrint中.\n"); fprintf(fp,"编号\t字符\t权值\tparent\tLChild\tRChild\n"); for(i=1;i<=m;i++){ fprintf(fp,"%d\t%c\t%d\t%d\t%d\t%d\n",i,(*ht)[i].data,(*ht)[i].weight,(*ht)[i].parent,(*ht)[i].LChild,(*ht)[i].RChild); } printf("存储成功! \n"); if(fclose(fp)){//关闭文件 printf("Cannotclosethefile! \n"); exit(0); } } voidPutCode(){ FILE*fp; charch; inti=0; if((fp=fopen("e: \\CodeFile.txt","r"))==NULL){//读取01代码输出文件CodeFile.txt中的代码 printf("Fileopenerror! \n"); exit(0); } while(! feof(fp)){ ch=fgetc(fp); if(ch! ='\0'){ printf("%c",ch); i=i+1; if(i%50==0) printf("\n"); } } if(fclose(fp)){//关闭文件 printf("Cannotclosethefile! \n"); exit(0); } } voidmain() { HuffmanTreeHT; HuffmanCodeHC; FILE*fp,*fps,*fpss; int*w; char*d,str[1000],s[2]; chardata,ch; inti,n,choice;//结点个数; intwei;//权值; intm,flag; intnLayer=0; printf("***********************************************************\n"); printf("***\t\t\t哈夫曼编译码\t\t\t***\n"); printf("***********************************************************\n"); do{ printf("***********************************************************\n"); printf("*\t\t输入你要选择的选项(请先选择1)\t\t*\n"); printf("*\t\t\t1.初始化哈夫曼树\t\t*\n"); printf("*\t\t\t2.对文件编码\t\t\t*\n"); printf("*\t\t\t3.对译文
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 哈夫曼编 译码