数据结构课程设计Huffman编译码器.docx
《数据结构课程设计Huffman编译码器.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计Huffman编译码器.docx(40页珍藏版)》请在冰豆网上搜索。
数据结构课程设计Huffman编译码器
课程设计(论文)任务书
软件 学院 软件工程 专业 2010-3 班
一、课程设计(论文)题目 数据结构课程设计(A)
二、课程设计(论文)工作自2011年12月22日起至2011年12月23日止。
三、课程设计(论文)地点:
软件学院机房
四、课程设计(论文)内容要求:
1.本课程设计的目的
(1)使学生熟练掌握抽象数据类型的组织和定义;
(2)使学生熟练掌握数据类型的定义和实现;
(3)培养学生组织和分析数据的能力;
(4)培养学生分析和应用基于不同数据结构的算法的能力;
(5)提高学生的科技论文写作能力。
2.基本要求:
每位同学在以下题目中任选一题(在方框中打勾),独立完成课程设计:
□集合的并交差运算:
参见《数据结构题集》P80。
□赫夫曼编/译码器:
参见《数据结构题集》P149。
□井字棋:
参见《数据结构》教材P2。
设计棋谱,当对方落子后,能从棋谱中选择一种
应对方式,并能判断胜负。
3.课程设计论文编写要求
(1)要按照书稿的规格打印誊写课设报告;
(2)报告分为封面、任务书(本文档)、正文、课程设计体会和参考文献四部分;
学生签名:
2011年12月23日
课程设计(论文)评审意见
(1)题目分析(20分):
优( )、良( )、中( )、一般( )、差( );
(2)流程分析 (30分):
(3)数据定义 (30分):
(4)代码编写 (10分):
(5)创新能力 (10分):
(6)格式规范性、设计态度及考勤是否降等级:
是( )、否( )
评阅人:
职称:
讲师
2012年1月5日
一、数据结构定义
1.抽象数据类型
本设计中用到的数据结构ADT定义如下:
ADTHuffmanTree{
数据对象D:
D是具有相同特性的数据元素集合。
数据关系R:
若D为空,则R为空,称Huffmantree为空赫夫曼树。
若D不为空,则R={H},H是如下的二元关系:
在D中存在惟一的称为根的数据元素
它在关系H下无前驱;
若
则存在
,且
;
则
中存在惟一的元素
,且存在
上的关系
;若
,则
;
是一棵符合本定义的赫夫曼树,称为根的左子树,
是一棵符合本定义的赫夫曼树,称为根的右子树;
基本操作P:
InputHuffman(HuffmanHfm)
操作结果:
输入并存储字符和相应权值。
Select(HuffmanTreeHT,intend,int*s1,int*s2)
初始条件:
频率数组已经建立。
选择HT[1....i-1]中无双亲且权值最小的两个节点,其序号为s1,s2。
HuffmanCoding(HuffmanHfm)
w存放n个字符的权值(均>0),构造赫夫曼树HT,并求出n个字符的构造赫夫曼编码HC。
InitHuffman(HuffmanHfm)
要求用户输入字符和相应权值,初始化赫夫曼数
Encoding(HuffmanHfm)
霍夫曼树HuffmanTree已经存在。
利用已建好的Huffman树(如不在内存,则从文件
hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
Decoding(HuffmanHfm)
利用已建好的Huffman树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
Print(HuffmanHfm)
霍夫曼树HoffmanTree已经存在。
将文件CodeFile以紧凑格式显示在终端上,每行50个代码。
Treeprint(HuffmanHfm)
将已在内存中的哈夫曼树以凹入表的形式显示在终端上同时将此字符形式的哈夫曼树写入文件TreePrint中。
}ADTHuffmanTree;
2.存储结构定义
数据存储结构的C语言定义如下:
ypedefchar**HuffmanCode;//动态分配数组存储哈夫曼表码表
typedefstruct{
unsignedintweight;
unsignedintparent,lchild,rchild;
}HTNode,*HuffmanTree;//动态分配数组存储哈夫曼树
HuffmanTreeHT;
char*c;
intlength;
HuffmanCodeHC;
}Huffman;
HuffmanHfm;//全局结构体变量,来存储字符与代码
3.基本操作
数据结构的基本操作实现如下:
/*输入函数,控制用户输入字符和相应权值*/
HuffmanInputHuffman(HuffmanHfm)
{
inti,n;
printf("\n\n********************Initialization*********************\n");
printf("Thecharsandweightswillbesavedinthefile:
\hfmTree\\n");
printf("Pleaseinputthenumberofthechars:
");
scanf("%d",&n);
if(n<=1)
/*若只有一个数值则无需编码*/
printf("OnlyOneChar!
ThereIsNoNeedForCoding!
printf("\n");
scanf("%d",&n);}
Hfm.HT=(HuffmanTree)malloc((2*n)*sizeof(HTNode));
Hfm.c=(char*)malloc((n+1)*sizeof(char));
for(i=1;i<=n;i++)
printf("Pleaseinputthechar:
scanf("%s",&Hfm.c[i]);
printf("Pleaseinputtheweightofthechar:
scanf("%d",&Hfm.HT[i].weight);
Hfm.HT[i].parent=0;
Hfm.HT[i].lchild=0;
Hfm.HT[i].rchild=0;
}
for(;i<=2*n-1;++i)
Hfm.HT[i].weight=0;
Hfm.length=n;
returnHfm;
/*选择HT[1....i-1]中无双亲且权值最小的两个节点,其序号为s1,s2*/
voidSelect(HuffmanTreeHT,intend,int*s1,int*s2)
inti;
intmin1=MAX_NUM;
intmin2;
for(i=1;i<=end;i++)//遍历查找权值最小的结点S1
if(HT[i].parent==0&&HT[i].weight{*s1=i;min1=HT[i].weight;}}min2=MAX_NUM;for(i=1;i<=end;i++)//遍历查找除S1外权值最小的结点S2{if(HT[i].parent==0&&(*s1!=i)&&min2>HT[i].weight){*s2=i;min2=HT[i].weight;}}}/***存放n个字符的权值(均〉0),构造哈夫曼树HT,*并求出n个字符的构造哈夫曼编码HC*/HuffmanHuffmanCoding(HuffmanHfm){inti,n,m,s1,s2,start;intc,f;char*cd;n=Hfm.length;if(n<=1)returnHfm;m=2*n-1;for(i=n+1;i<=m;++i){Select(Hfm.HT,i-1,&s1,&s2);Hfm.HT[s1].parent=i;//修改父亲位置Hfm.HT[s2].parent=i;Hfm.HT[i].lchild=s1;//修改孩子位置Hfm.HT[i].rchild=s2;/*父亲结点权值为左右孩子权值之和*/Hfm.HT[i].weight=Hfm.HT[s1].weight+Hfm.HT[s2].weight;}/*从叶子结点到根逆向求每个字符的哈夫曼编码*/Hfm.HC=(HuffmanCode)malloc((n+1)*sizeof(char*));cd=(char*)malloc(n*sizeof(char));//分配求编码的工作空间cd[n-1]='\0';//编码结束符for(i=1;i<=n;++i)//逐个字符求哈夫曼编码{start=n-1;//编码结束符位置/*从叶子到根逆向求编码*/for(c=i,f=Hfm.HT[i].parent;f!=0;c=f,f=Hfm.HT[f].parent){if(c==Hfm.HT[f].lchild)cd[--start]='0';elsecd[--start]='1';}Hfm.HC[i]=(char*)malloc((n-start)*sizeof(char));strcpy(Hfm.HC[i],&cd[start]);//从cd复制编码到Hfm.HC}free(cd);//释放工作空间returnHfm;}/*初始化哈夫曼数,要求用户输入字符和相应权值*/HuffmanInitHuffman(HuffmanHfm){intn,i;charx;FILE*fp;fp=fopen("hfmTree.txt","r+");//对文件hfmTree以读文本的形式打开if(fp==NULL)printf("OpenhfmTree.txterror!");Hfm=InputHuffman(Hfm);fp=fopen("hfmTree.txt","w+");fprintf(fp,"%d\n",Hfm.length);for(i=1;i<=Hfm.length;i++)fprintf(fp,"%c%d",Hfm.c[i],Hfm.HT[i].weight);rewind(fp);fclose(fp);Hfm=HuffmanCoding(Hfm);returnHfm;}voidEncoding(HuffmanHfm){inti=0,j=0,n;charch[MAX];FILE*fp,*fw;n=Hfm.length;printf("\n\n*******************Encoding************************\n\n");if((fw=fopen("ToBeTran.txt","r+"))==NULL){printf("\nPleaseinputthesentence:");scanf("%s",ch);printf("\n");fp=fopen("CodeFile.txt","w+");}else{fscanf(fw,"%s",ch);fclose(fw);}while(ch[j]){for(i=1;i<=n;i++)if(ch[j]==Hfm.c[i]){printf("%s",Hfm.HC[i]);fprintf(fp,"%s",Hfm.HC[i]);break;}j++;}printf("\n");rewind(fp);fclose(fp);}voidDecoding(HuffmanHfm){HuffmanTreep;inti,n;intj=0;chard[500];FILE*fp;n=Hfm.length;printf("\n\n******************Decoding************************\n\n");if((fp=fopen("CodeFile.txt","r+"))==NULL){printf("Pleaseinputthecode:");scanf("%s",d);}else{fscanf(fp,"%s",d);//将文件中的字符输入到数组d中fclose(fp);}printf("\nThefileis:");fp=fopen("TextFile.txt","w+");//以写入文件的形式打开TextFilewhile(d[j]){p=&Hfm.HT[2*n-1];while(p->lchild||p->rchild){if(d[j]=='0'){i=p->lchild;p=&Hfm.HT[i];}else{i=p->rchild;p=&Hfm.HT[i];}j++;}printf("%c",Hfm.c[i]);fprintf(fp,"%c",Hfm.c[i]);}printf("\n");fclose(fp);}voidPrint(HuffmanHfm){inti,n;intm=1;//计数器charch;FILE*fprint,fp;n=Hfm.length;printf("\n\n************Outputthecodeofthechars************\n");for(i=1;i<=n;i++)//显示每一个字符对应的哈夫曼编码{printf("\n");printf("Char:%c\t",Hfm.c[i]);printf("Weight:%d\t",Hfm.HT[i].weight);printf("Code:");puts(Hfm.HC[i]);}fprint=fopen("CodeFile.txt","rb");//fp=fopen("CodePrint.txt","w+");while(feof(fprint)==0){ch=fgetc(fprint);printf("%c",ch);//fprintf(fp,"%c",ch);m++;if(m%50==0)//保证每一行输出50个字符printf("\n");}printf("\n\n");fclose(fprint);}voidConvert_tree(unsignedcharT[100][100],ints,int*i,intj){intk,m;HuffmanHfm;m=++(*i);for(k=0;kT[m][k]='';T[m][k]=Hfm.HT[j].weight;if(Hfm.HT[j].lchild)Convert_tree(T,s+1,i,Hfm.HT[j].lchild);if(Hfm.HT[j].rchild)Convert_tree(T,s+1,i,Hfm.HT[j].rchild);T[m][++k]='\0';}voidTreeprinting(HuffmanHfm){unsignedcharT[100][100];intn=Hfm.length;inti,j,m=0;FILE*fp;Convert_tree(T,0,&m,2*n-1);if((fp=fopen("treeprint.txt","wb+"))==NULL)printf("Openfiletreeprint.txterror!\n");printf("\n以凹入表形式打印已建好的赫夫曼树:\n");for(i=1;i<=2*n-1;i++){for(j=0;T[i][j]!=0;j++){if(T[i][j]==''){printf("");fputc(T[i][j],fp);}else{printf("%d",T[i][j]);fprintf(fp,"%d\n",T[i][j]);}}printf("\n");}fclose(fp);printf("\n此字符形式的哈夫曼树已写入文件treeprint.txt中.\n\n");}二、解题过程1.问题分解该问题主要应实现以下功能:(1)I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立赫夫曼树,并将它存于文件hfmTree中。(2)E:编码(Encoding)。利用已建好的赫夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。(3)D:译码(Decoding)。利用已建好的赫夫曼树将文件CodeFile中的代码进行译码,结果存入文件Textfile中。(4)P:印代码文件(Print)。将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件CodePrin中。(5)T:印赫夫曼树(Treeprinting)。将已在内存中的赫夫曼树以直观的方式(比如树)显示在终端上,同时将此字符形式的赫夫曼树写入文件TreePrint中。2.模块结构系统主要由6个模块组成,如图所示: 模块之间的结构如下:3.解题思路各模块的实现步骤为:.主程序main(){InitHuffman(HuffmanHfm);Encoding(HuffmanHfm);Decoding(HuffmanHfm);Print(HuffmanHfm);Treeprint(HuffmanHfm);}.其他模块:voidSelect(HuffmanTreeHT,intend,int*s1,int*s2){FOR(i=1;i<=end;i++){IF(HT[i].parent是最小的)THENHT[i].parent——>*s1IF(HT[i].parent是次最小的)THENHT[i].parent——>*s2}}HuffmanHuffmanCoding(HuffmanHfm){FOR(i=n+1;i<=2*n-1;++i){Select(Hfm.HT,i-1,&s1,&s2);修改父亲位置;修改孩子位置;父亲结点权值为左右孩子权值之和;}/*从叶子结点到根逆向求每个字符的赫夫曼编码*/FOR(i=1;i<=n;++i)//逐个字符求赫夫曼编码{start=n-1;//编码结束符位置for(c=i,f=Hfm.HT[i].parent;f!=0;c=f,f=Hfm.HT[f].parent){IF(c==Hfm.HT[f].lchild)cd[--start]='0';ELSEcd[--start]='1';}再从cd复制编码到Hfm.HC}RETURNHfm;}HuffmanInitHuffman(HuffmanHfm){对文件hfmTree以读文本的形式打开IF(fp==NULL)调用InputHuffman函数,用户输入字符和相应权值存入赫夫曼数中ELSE输出"TheHuffmantreehasalreadyexisted!\nPleasechooseagain!\n\n");读入hfmTree中文本FOR(i=1;i<=n;i++)作为独立结点对结点的parent,lchild,rchild分别赋值0FOR(;i<=2*n-1;++i)作为独立结点对结点的weight,parent,lchild,rchild分别赋值0Hfm=HuffmanCoding(Hfm);RETURNHfm;}voidEncoding(HuffmanHfm){输出"\n\n*
*s1=i;
min1=HT[i].weight;
min2=MAX_NUM;
for(i=1;i<=end;i++)//遍历查找除S1外权值最小的结点S2
if(HT[i].parent==0&&(*s1!
=i)&&min2>HT[i].weight)
*s2=i;
min2=HT[i].weight;
/**
*存放n个字符的权值(均〉0),构造哈夫曼树HT,
*并求出n个字符的构造哈夫曼编码HC
*/
HuffmanHuffmanCoding(HuffmanHfm)
inti,n,m,s1,s2,start;
intc,f;
char*cd;
n=Hfm.length;
if(n<=1)returnHfm;
m=2*n-1;
for(i=n+1;i<=m;++i)
Select(Hfm.HT,i-1,&s1,&s2);
Hfm.HT[s1].parent=i;//修改父亲位置
Hfm.HT[s2].parent=i;
Hfm.HT[i].lchild=s1;//修改孩子位置
Hfm.HT[i].rchild=s2;
/*父亲结点权值为左右孩子权值之和*/
Hfm.HT[i].weight=Hfm.HT[s1].weight+Hfm.HT[s2].weight;
/*从叶子结点到根逆向求每个字符的哈夫曼编码*/
Hfm.HC=(HuffmanCode)malloc((n+1)*sizeof(char*));
cd=(char*)malloc(n*sizeof(char));//分配求编码的工作空间
cd[n-1]='\0';//编码结束符
for(i=1;i<=n;++i)//逐个字符求哈夫曼编码
start=n-1;//编码结束符位置
/*从叶子到根逆向求编码*/
for(c=i,f=Hfm.HT[i].parent;f!
=0;c=f,f=Hfm.HT[f].parent)
if(c==Hfm.HT[f].lchild)
cd[--start]='0';
else
cd[--start]='1';
Hfm.HC[i]=(char*)malloc((n-start)*sizeof(char));
strcpy(Hfm.HC[i],&cd[start]);//从cd复制编码到Hfm.HC
free(cd);//释放工作空间
/*初始化哈夫曼数,要求用户输入字符和相应权值*/
HuffmanInitHuffman(HuffmanHfm)
intn,i;charx;
FILE*fp;
fp=fopen("hfmTree.txt","r+");//对文件hfmTree以读文本的形式打开
if(fp==NULL)
printf("OpenhfmTree.txterror!
Hfm=InputHuffman(Hfm);
fp=fopen("hfmTree.txt","w+");
fprintf(fp,"%d\n",Hfm.length);
for(i=1;i<=Hfm.length;i++)
fprintf(fp,"%c%d",Hfm.c[i],Hfm.HT[i].weight);
rewind(fp);
fclose(fp);
Hfm=HuffmanCoding(Hfm);
voidEncoding(HuffmanHfm)
inti=0,j=0,n;
charch[MAX];
FILE*fp,*fw;
printf("\n\n*******************Encoding************************\n\n");
if((fw=fopen("ToBeTran.txt","r+"))==NULL)
printf("\nPleaseinputthesentence:
scanf("%s",ch);
fp=fopen("CodeFile.txt","w+");
fscanf(fw,"%s",ch);
fclose(fw);
while(ch[j])
if(ch[j]==Hfm.c[i])
printf("%s",Hfm.HC[i]);
fprintf(fp,"%s",Hfm.HC[i]);
break;
j++;
voidDecoding(HuffmanHfm)
HuffmanTreep;
intj=0;
chard[500];
printf("\n\n******************Decoding************************\n\n");
if((fp=fopen("CodeFile.txt","r+"))==NULL)
printf("Pleaseinputthecode:
scanf("%s",d);
fscanf(fp,"%s",d);//将文件中的字符输入到数组d中
printf("\nThefileis:
fp=fopen("TextFile.txt","w+");//以写入文件的形式打开TextFile
while(d[j])
p=&Hfm.HT[2*n-1];
while(p->lchild||p->rchild)
if(d[j]=='0')
{i=p->lchild;p=&Hfm.HT[i];}
{i=p->rchild;p=&Hfm.HT[i];}
printf("%c",Hfm.c[i]);
fprintf(fp,"%c",Hfm.c[i]);
voidPrint(HuffmanHfm)
intm=1;//计数器
charch;
FILE*fprint,fp;
printf("\n\n************Outputthecodeofthechars************\n");
for(i=1;i<=n;i++)//显示每一个字符对应的哈夫曼编码
printf("Char:
%c\t",Hfm.c[i]);
printf("Weight:
%d\t",Hfm.HT[i].weight);
printf("Code:
puts(Hfm.HC[i]);
fprint=fopen("CodeFile.txt","rb");//fp=fopen("CodePrint.txt","w+");
while(feof(fprint)==0)
ch=fgetc(fprint);
printf("%c",ch);
//fprintf(fp,"%c",ch);
m++;
if(m%50==0)//保证每一行输出50个字符
printf("\n\n");
fclose(fprint);
voidConvert_tree(unsignedcharT[100][100],ints,int*i,intj)
intk,m;HuffmanHfm;
m=++(*i);
for(k=0;k
T[m][k]='';
T[m][k]=Hfm.HT[j].weight;
if(Hfm.HT[j].lchild)
Convert_tree(T,s+1,i,Hfm.HT[j].lchild);
if(Hfm.HT[j].rchild)
Convert_tree(T,s+1,i,Hfm.HT[j].rchild);
T[m][++k]='\0';
voidTreeprinting(HuffmanHfm)
unsignedcharT[100][100];
intn=Hfm.length;
inti,j,m=0;
Convert_tree(T,0,&m,2*n-1);
if((fp=fopen("treeprint.txt","wb+"))==NULL)
printf("Openfiletreeprint.txterror!
\n");
printf("\n以凹入表形式打印已建好的赫夫曼树:
for(i=1;i<=2*n-1;i++)
for(j=0;T[i][j]!
=0;j++)
if(T[i][j]=='')
printf("");
fputc(T[i][j],fp);
printf("%d",T[i][j]);
fprintf(fp,"%d\n",T[i][j]);
printf("\n此字符形式的哈夫曼树已写入文件treeprint.txt中.\n\n");
二、解题过程
1.问题分解
该问题主要应实现以下功能:
(1)I:
初始化(Initialization)。
从终端读入字符集大小n,以及n个字符和n个
权值,建立赫夫曼树,并将它存于文件hfmTree中。
(2)E:
编码(Encoding)。
利用已建好的赫夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件
CodeFile中。
(3)D:
译码(Decoding)。
利用已建好的赫夫曼树将文件CodeFile中的代码进
行译码,结果存入文件Textfile中。
(4)P:
印代码文件(Print)。
将文件CodeFile以紧凑格式显示在终端上,每行
50个代码。
同时将此字符形式的编码文件写入文件CodePrin中。
(5)T:
印赫夫曼树(Treeprinting)。
将已在内存中的赫夫曼树以直观的方式(比如树)显示在终端上,同时将此字符形式的赫夫曼树写入文件TreePrint中。
2.模块结构
系统主要由6个模块组成,如图所示:
模块之间的结构如下:
3.解题思路
各模块的实现步骤为:
.主程序
main()
InitHuffman(HuffmanHfm);
Encoding(HuffmanHfm);
Decoding(HuffmanHfm);
Print(HuffmanHfm);
Treeprint(HuffmanHfm);
.其他模块:
FOR(i=1;i<=end;i++)
IF(HT[i].parent是最小的)
THENHT[i].parent——>*s1
IF(HT[i].parent是次最小的)
THENHT[i].parent——>*s2
FOR(i=n+1;i<=2*n-1;++i)
修改父亲位置;
修改孩子位置;
父亲结点权值为左右孩子权值之和;
/*从叶子结点到根逆向求每个字符的赫夫曼编码*/
FOR(i=1;i<=n;++i)//逐个字符求赫夫曼编码
IF(c==Hfm.HT[f].lchild)
ELSE
再从cd复制编码到Hfm.HC
RETURNHfm;
对文件hfmTree以读文本的形式打开
IF(fp==NULL)
调用InputHuffman函数,用户输入字符和相应权值存入赫夫曼数中
输出"TheHuffmantreehasalreadyexisted!
\nPleasechooseagain!
\n\n");
读入hfmTree中文本
FOR(i=1;i<=n;i++)
作为独立结点对结点的parent,lchild,rchild分别赋值0
FOR(;i<=2*n-1;++i)
作为独立结点对结点的weight,parent,lchild,rchild分别赋值0
输出"\n\n*
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1