数据结构课程设计赫夫曼编码.docx
《数据结构课程设计赫夫曼编码.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计赫夫曼编码.docx(18页珍藏版)》请在冰豆网上搜索。
![数据结构课程设计赫夫曼编码.docx](https://file1.bdocx.com/fileroot1/2023-1/23/9d4c80f5-6be6-4383-ac4c-50dae307b390/9d4c80f5-6be6-4383-ac4c-50dae307b3901.gif)
数据结构课程设计赫夫曼编码
中南民族大学
数据结构课程设计报告
*******
年级:
2010
学号:
*******4
专业:
计算机科学与技术
*******
2013年4月15日
实习报告:
赫夫曼编/译码器
题目:
为信息收发站写一个赫夫曼码的编/译码系统
班级:
计科一班姓名:
康宇学号:
*******4完成日期:
2013.4.5
一、需求分析
1、问题描述:
利用赫夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端讲传来的数据进行译码(复原)。
对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。
2、基本要求:
(1)I:
初始化(Initialization)。
从终端读入字符集大小n,以及n个字符和n个权值,建立赫夫曼树,并将它存于文件hfmTree中。
(2)E:
编码(Encoding)。
利用已建好的赫夫曼树,对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
(3)D:
译码(Decoding)。
利用已建好的赫夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
(4)P:
印代码文件(Print)。
将文件CodeFile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件CodePrin中。
(5)T:
印赫夫曼树(TreePrinting)。
将已在内存中的赫夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的赫夫曼树写入文件TreePrint中。
3、实现提示:
(1)编码结果以文本方式存储在文件CodeFile中。
(2)用户界面可以设计为“菜单”方式:
显示上述功能符号,再加上“Q”,表示退出运行Quit。
请用户键入一个选择功能符。
此功能执行完毕后再显示此菜单,直至某次用户选择了“Q”为止。
二、概要设计
1.元素类型:
typedefstruct
{
intweigt;//权值
intparent,lchild,rchild;//双亲,左孩子,右孩子
}HTNode,*HuffmanTree;
typedefchar**HuffmanCode;//存放各个字符的前缀编码
2.本程序包括六个大板块:
(1)主程序:
intmain()
{
输出菜单;
选择功能选项并调用对应的函数;
}
(2)初始化函数:
voidInitialization(HuffmanTree&ht,FILE*fp)
{
安全打开文件;
输入字符数量以及各字符及其权值;
对各节点进行初始化;
创建赫夫曼列表;(需要调用Select()函数选择权职最小的两个节点)
}
voidSelect(HuffmanTree&ht,inti,int&s_1,int&s_2)
{
找出第一个非零结点;
找出第二个非零结点;
遍历比较找出权值最小的两个节点;
}
(3)编码函数:
voidEncoding(HuffmanTree&ht,HuffmanCode&hc,FILE*fp1,FILE*fp2)
{
安全打开文件;
for:
1n,双亲不为空
If(为左孩子)
str[--start]='0';
else
str[--start]='1';
储存各字符的编码;
从文件中读取正文;
依次遍历正文各字符,显示其编码;
}
(4)译码函数:
voidDecoding(HuffmanTree&ht,HuffmanCode&hc,FILE*fp1,FILE*fp2)
{
安全打开文件;
While(成功读取字符)
{
遍历目前的编码中是否有对应的字符;
if(有)
输出该字符;
else
跳到循环体首;(再次读入一个字符再判断)
}
}
(5)印代码文件:
voidPrint(FILE*fp1,FILE*fp2)
{
安全打开文件;
从文件中读取字符,50个一行输出;
}
(6)印赫夫曼树:
voidTreeprinting(HuffmanTreeht)
{
安全打开文件;
调用print_tree(ht,root)函数;
}
voidprint_tree(HuffmanTreeht,intr)
{
if(存在节点)
{
深度+1;
递归调用print_tree(ht,ht[r].rchild);//先输出右子树
用深度控制格式;
输出对应的字符;
递归调用print_tree(ht,ht[r].lchild);//再输出左子树
深度-1
}
}
三、详细设计
#include
#include
#include
typedefstruct
{
intweigt;
intparent,lchild,rchild;
}HTNode,*HuffmanTree;
typedefchar**HuffmanCode;//存放各个字符的前缀编码
//此全局文件指针用于输出赫夫曼树到对应文件,便于调用递归
FILE*TreePrint=NULL;
char*s;//存放各字符
int*w;//存放各字符的权值
intn;
intm;
intdep=0;//存放各字符的深度
voidSelect(HuffmanTree&ht,inti,int&s_1,int&s_2)//挑选出权值最小的两个结点
{
intj;
for(j=1;j<=i;j++)//找出第一个非零结点
if(ht[j].parent==0)
{
s_1=j;
break;
}
for(j=s_1+1;j<=i;j++)//找出第二个非零结点
if(ht[j].parent==0)
{
s_2=j;
break;
}
for(j=1;j<=i;j++)//遍历出权值最小的两个结点
{
if(ht[j].parent==0)//必须要判断双亲是否为空
{
if(ht[j].weigt{
s_2=s_1;
s_1=j;
}
elseif(ht[j].weigt>ht[s_1].weigt&&ht[j].weigt{
s_2=j;
}
}
}
}
voidInitialization(HuffmanTree&ht,FILE*fp)
{
inti,s1,s2;
if((fp=fopen("hfmTree.txt","w"))==NULL)//安全打开文件
{
printf("FilehfmTree.txtcannotopened.\n");
exit
(1);
}
//输入各字符以及权值
printf("请输入字符集大小n:
");
scanf("%d",&n);
s=(char*)malloc(n*sizeof(char));
w=(int*)malloc(n*sizeof(int));
printf("请输入各字符:
\n");
getchar();
//getchar();//处理换行符
//scanf("%s",s);
gets(s);
printf("请输入各字符对应的权值:
\n");
for(i=0;iscanf("%d",&w[i]);
if(n<=1)
return;
m=2*n-1;//节、结点的个数
ht=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
for(i=1;i<=n;i++)//分别对各结点赋值
{
ht[i].weigt=w[i-1];
ht[i].parent=ht[i].lchild=ht[i].rchild=0;
}
for(i=n+1;i<=m;i++)
{
ht[i].weigt=ht[i].parent=ht[i].lchild=ht[i].rchild=0;
}
//构建赫夫曼树
for(i=n+1;i<=m;i++)
{
Select(ht,i-1,s1,s2);//选出权值最小的叶子节点
ht[s1].parent=ht[s2].parent=i;
ht[i].lchild=s1;
ht[i].rchild=s2;
ht[i].weigt=ht[s1].weigt+ht[s2].weigt;//构建新结点的权值
}
//输出赫夫曼列表
printf("赫夫曼列表为:
\n");
for(i=1;i<=n;i++)//叶子节点
{
fprintf(fp,"\t%c\t%d\t%d\t%d\t%d\n",s[i],ht[i].weigt,ht[i].parent,ht[i].lchild,ht[i].rchild);
printf("\t%c\t%d\t%d\t%d\t%d\n",s[i-1],ht[i].weigt,ht[i].parent,ht[i].lchild,ht[i].rchild);
}
for(i=n+1;i<=m;i++)//非叶子节点
{
fprintf(fp,"\t\t%d\t%d\t%d\t%d\n",ht[i].weigt,ht[i].parent,ht[i].lchild,ht[i].rchild);
printf("\t\t%d\t%d\t%d\t%d\n",ht[i].weigt,ht[i].parent,ht[i].lchild,ht[i].rchild);
}
fclose(fp);
}
voidEncoding(HuffmanTree&ht,HuffmanCode&hc,FILE*fp1,FILE*fp2)//编码
{
inti,j,c,f,start;
char*str;//用于存放编码
chardata[100];//用于存放文件正文字符
if((fp1=fopen("ToBeTran.txt","r"))==NULL)
{
printf("FileToBeTran.txtcannotopened.\n");
exit
(1);
}
if((fp2=fopen("CodeFile.txt","w"))==NULL)
{
printf("FileCodeFile.txtcannotopened.\n");
exit
(1);
}
//根据赫夫曼树得到各字符对应的编码
hc=(HuffmanCode)malloc((n+1)*sizeof(char*));
str=(char*)malloc(n*sizeof(char));//n个字符中的最长的编码个数为n-1
str[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)//为左子树
str[--start]='0';
else//为右子树
str[--start]='1';
}
hc[i]=(char*)malloc((n-start)*sizeof(char));
strcpy(hc[i],&str[start]);//赋值对应字符的编码
}
printf("各字符串的编码为:
\n");
for(i=1;i<=n;i++)
{
printf("%s\n",hc[i]);
}
//对文件正文进行编码
//fscanf(fp1,"%s",data);
fgets(data,500,fp1);//读取正文
printf("文件正文为:
");
printf("%s",data);
printf("\n文件ToBeTran中的正文编码为:
\n");
for(i=0;i{
for(j=0;jif(data[i]==s[j])//依次遍历出正文各字符的编码,并存储到文件中
{
printf("%s",hc[j+1]);
fprintf(fp2,"%s",hc[j+1]);
break;
}
}
printf("\n");
free(str);
fclose(fp1);
fclose(fp2);
}
voidDecoding(HuffmanTree&ht,HuffmanCode&hc,FILE*fp1,FILE*fp2)
{
inti,j;
boolflag;
charch;
char*data=(char*)malloc(n*sizeof(char));//临时存放赫夫曼码
if((fp1=fopen("CodeFile.txt","r"))==NULL)
{
printf("FileCodeFile.txtcannotopened.\n");
exit
(1);
}
if((fp2=fopen("TextFile.txt","w"))==NULL)
{
printf("FileTextFile.txtcannotopened.\n");
exit
(1);
}
//进行译码
printf("文件译码为:
\n");
while(fscanf(fp1,"%c",&ch)!
=EOF)//有编码可读取
{
flag=true;//控制循环
i=0;
while(flag)
{
if(i!
=0)
fscanf(fp1,"%c",&ch);
data[i++]=ch;
data[i]='\0';
for(j=1;j<=n;j++)
if(!
strcmp(data,hc[j]))//如果找到匹配的字符编码
{
printf("%c",s[j-1]);
fprintf(fp2,"%c",s[j-1]);
flag=false;
break;
}
}
}
fclose(fp1);
fclose(fp2);
}
voidPrint(FILE*fp1,FILE*fp2)
{
charch;
intsum=0;
if((fp1=fopen("CodeFile.txt","r"))==NULL)
{
printf("FileCodeFile.txtcannotopened.\n");
exit
(1);
}
if((fp2=fopen("CodePrin.txt","w"))==NULL)
{
printf("FileCodePrin.txtcannotopened.\n");
exit
(1);
}
//从CodeFile中读取出来输出到CodePrin中
printf("文件字符为:
\n");
while(fscanf(fp1,"%c",&ch)!
=EOF)
{
sum++;
printf("%c",ch);
fprintf(fp2,"%c",ch);
if(sum%50==0)//50个字符一行
{
printf("\n");
fprintf(fp2,"\n");
}
}
fclose(fp1);
fclose(fp2);
}
voidprint_tree(HuffmanTreeht,intr)
{
//左倒置90度输出到文件和终端上
if(r)
{
dep++;//控制叶子节点的深度
print_tree(ht,ht[r].rchild);//先输出右子树
for(inti=1;i{
printf("\t");
fprintf(TreePrint,"\t");
}
if(r>n)
{
printf("O\n");
fprintf(TreePrint,"O\n");
}
else
{
printf("%c\n",s[r-1]);
fprintf(TreePrint,"%c\n",s[r-1]);
}
print_tree(ht,ht[r].lchild);//再输出左子树
dep--;
}
}
voidTreeprinting(HuffmanTreeht)
{
introot;//根结点
if((TreePrint=fopen("TreePrint.txt","a"))==NULL)//进行数据追加
{
printf("FileTreePrint.txtcannotopened.\n");
exit
(1);
}
root=m;
printf("赫夫曼树为:
\n");
print_tree(ht,root);
fclose(TreePrint);//及时关闭文件
}
intmain()
{
intchoose;
FILE*hfmTree=NULL,*ToBeTran=NULL,*CodeFile=NULL,*TextFile=NULL,*CodePrin=NULL;
HuffmanTreehuftree=NULL;//指针初始化
HuffmanCodehufcode=NULL;
while
(1)
{
printf("\n------------------赫夫曼编/译码器菜单---------------------\n");
printf("1-----------------Initialization(初始化)\n");
printf("2-----------------Encoding(编码)\n");
printf("3-----------------Decoding(译码)\n");
printf("4-----------------Print(印代码文件)\n");
printf("5-----------------Treeprinting(印赫夫曼树)\n");
printf("0-----------------Quit(退出)\n");
printf("-----------------------------------------------------------\n");
printf("请选择功能:
");
scanf("%d",&choose);
switch(choose)
{
case1:
Initialization(huftree,hfmTree);
break;
case2:
Encoding(huftree,hufcode,ToBeTran,CodeFile);
break;
case3:
Decoding(huftree,hufcode,CodeFile,TextFile);
break;
case4:
Print(CodeFile,CodePrin);
break;
case5:
Treeprinting(huftree);
break;
case0:
printf("退出!
!
\n");
exit
(1);
default:
printf("请重新输入!
!
\n");
}
}
free(hfmTree);
free(ToBeTran);
free(CodeFile);
free(TextFile);
free(CodePrin);
free(TreePrint);
return0;
}
四、调试分析
1.本次作业还是有一定的难度的,核心算法在于怎样建立赫夫曼树以及怎样由赫夫曼树得到前缀编码。
如果这两个问题解决后,问正文进行编码或译码就很简单了,还有一个难点是:
怎样把赫夫曼树以树状的形式输出。
对文件的调用也要引起注意,小心调用。
2.本程序模块简洁,在main()函数里得到充分体现,菜单显示各功能,各函数功能独立性强,便于修改。
3.用户可任意输入字符个数以及各字符权值,便于用户体验系统的完整性。
本程序具有一定的普遍性。
五、用户手册
1.本程序运行环境为Windows操作系统,执行文件为:
赫夫曼编译码.exe
2.进入演示程序后显示的界面:
六、测试结果