数据结构课程设计赫夫曼编码.docx

上传人:b****5 文档编号:7474964 上传时间:2023-01-24 格式:DOCX 页数:18 大小:84.95KB
下载 相关 举报
数据结构课程设计赫夫曼编码.docx_第1页
第1页 / 共18页
数据结构课程设计赫夫曼编码.docx_第2页
第2页 / 共18页
数据结构课程设计赫夫曼编码.docx_第3页
第3页 / 共18页
数据结构课程设计赫夫曼编码.docx_第4页
第4页 / 共18页
数据结构课程设计赫夫曼编码.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

数据结构课程设计赫夫曼编码.docx

《数据结构课程设计赫夫曼编码.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计赫夫曼编码.docx(18页珍藏版)》请在冰豆网上搜索。

数据结构课程设计赫夫曼编码.docx

数据结构课程设计赫夫曼编码

中南民族大学

 

数据结构课程设计报告

 

*******

年级:

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;i

scanf("%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;j

if(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.进入演示程序后显示的界面:

六、测试结果

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 农林牧渔 > 林学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1