哈夫曼树应用 1.docx
《哈夫曼树应用 1.docx》由会员分享,可在线阅读,更多相关《哈夫曼树应用 1.docx(30页珍藏版)》请在冰豆网上搜索。
![哈夫曼树应用 1.docx](https://file1.bdocx.com/fileroot1/2023-2/25/019c0a76-5ba5-48b1-a997-8070170de004/019c0a76-5ba5-48b1-a997-8070170de0041.gif)
哈夫曼树应用1
课程设计任务书
2010~2011学年第1学期
学生姓名:
**专业班级:
**********
指导教师:
*****工作部门:
计算机学院
一、课程设计题目:
哈夫曼树应用
二、课程设计要求:
1)从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树并将它存于文件hfmTree中.将已在内存中的哈夫曼树以直观的方式(比如树)显示在终端上;
2)利用已经建好的哈夫曼树(如不在内存,则从文件htmTree中读入),对文件Text.txt中的正文进行编码,然后将结果存入文件Code.txt中。
3)利用已建好的哈夫曼树将文件Code.txt中的代码进行译码,结果存入文件Text.txt中,并输出结果。
三、进度安排
1.分析问题,给出数学模型,选择数据结构。
2.设计算法,给出算法描述,给出源程序清单。
3.编辑、编译、调试源程序,撰写课程设计报告。
四、基本要求
1.界面友好,函数功能要划分好
2.总体设计应画一流程图
3.程序要加必要的注释
4.要提供程序测试方案
5.程序一定要经得起测试,宁可功能少一些,也要能运行起来,不能运行的程序是没有价值的。
1·设计目的
数据结构作为一门学科主要研究数据的各种逻辑结构和存储结构,以及对数据的各种操作。
因此,主要有三个方面的内容:
数据的逻辑结构;数据的物理存储结构;对数据的操作(或算法)。
通常,算法的设计取决于数据的逻辑结构,算法的实现取决于数据的物理存储结构。
数据结构是信息的一种组织方式,其目的是为了提高算法的效率,它通常与一组算法的集合相对应,通过这组算法集合可以对数据结构中的数据进行某种操作。
在当今信息时代,信息技术己成为当代知识经济的核心技术。
我们时刻都在和数据打交道。
比如人们在外出工作时找最短路径,在银行查询存款、通过互联网查新闻、以及远程教育报名等,所有这些都在与数据发生关系。
实际上,现实世界中的实体经过抽象以后,就可以成为计算机上所处理的数据。
数据结构课程主要是研究非数值计算的程序设计问题中所出现的计算机操作对象以及它们之间的关系和操作的学科。
数据结构是介于数学、计算机软件和计算机硬件之间的一门计算机专业的核心课程,它是计算机程序设计、数据库、操作系统、编译原理及人工智能等的重要基础,广泛的应用于信息学、系统工程等各种领域。
学习数据结构是为了将实际问题中所涉及的对象在计算机中表示出来并对它们进行处理。
通过课程设计可以提高学生的思维能力,促进学生的综合应用能力和专业素质的提高。
通过此次课程设计主要达到以下目的:
一、了解并掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力;
二、初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能;
三、提高综合运用所学的理论知识和方法独立分析和解决问题的能力;
四、训练用系统的观点和软件开发一般规范进行软件开发,培养软件工作者所应具备的科学的工作方法和作风。
2.需求分析
2.1哈夫曼编码/译码器简介
举例说明,先前快速远距离通信的主要手段是电报,即将需传送的文字转换成由二进制的字符组成的字符串。
在传送电文时,希望总长尽可能地短,如果对每个字符设计长度不等的编码,且让电文中出现次数较多的字符采用尽可能短的编码,以减少经费。
哈夫曼树就是根据此原理设计出来的一种存储结构。
本次要做的哈夫曼编码/译码器的主要功能是:
运用二叉树来设计二进制的前缀编码。
若给一个文件,先统计文件中每个字符出现的频数,即作为此字符的权值,然后将里面的字符编码成相应的哈夫曼编码;反之,根据哈夫曼译码原理把所给二进制数编译成对应的字符串。
2.2.问题描述
1.从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树并将它存于文件hfmTree中.将已在内存中的哈夫曼树以直观的方式(比如树)显示在终端上;
2.利用已经建好的哈夫曼树(如不在内存,则从文件htmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中,并输出结果,将文件CodeFile以紧凑格式先是在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件CodePrint中。
3.利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
2.3需求分析
一个完整的系统应具有以下功能:
1)I:
初始化(Initialization)。
从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
输出哈夫曼树,及各字符对应的编码。
2)W:
输入(Input)。
从终端读入需要编码的字符串s,将字符串s存入文件Tobetran.txt中。
3)E:
编码(Encoding)与译码(Decoding)。
编码(Encoding)。
利用已建好的哈夫曼树(如不在内存,则从文件htmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
译码(Decoding)。
利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
印代码文件(Print)。
将文件CodeFile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码写入文件CodePrint中。
4)T:
印哈夫曼树(TreePrinting)。
将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
5)Q:
退出程序。
返回WINDOWS界面。
3.概要设计
3.1问题分析哈夫曼树的定义
typedefstructHuffmantree
{
charch;/*键值*/
intweight,mark;/*weight为权值,mark为标志域*/
structHuffmantree*parent,*lchild,*rchild,*next;/*结构指针*/
}Hftree,*linktree;
使用链树存储,然后分别调用统计频数函数,排序函数,建立哈夫曼函数,编码函数,译码函数来实现功能。
4.详细设计
4.1系统框架图
对系统进行分析,给出系统结构图。
如图4.1
z
图4.1系统流程图
4.2总体流程图
哈夫曼树算法的总体流程图如图4.2
Case1Case2
Case2
Case1
图4.2总体流程图
4.3编码函数
以下是源程序中实现编码的部分:
voidHuffmancoding(linktreetree)
{
intindex=0;
char*code;
linktreeptr=tree;
code=(char*)malloc(10*sizeof(char));/*此数组用于统计哈夫曼编码*/
printf("字符以及它的相应权数---------哈夫曼编码\n\n");
if(ptr==NULL)
{
cout<<"哈夫曼树是空的!
\n";
exit(0);
}
else
{
while(ptr->lchild&&ptr->rchild&&ptr->mark==0)
{
while(ptr->lchild&&ptr->lchild->mark==0)
{
code[index++]='0';
ptr=ptr->lchild;
if(!
ptr->lchild&&!
ptr->rchild//打印哈夫曼树中的结点
{
ptr->mark=1;
code[index]='\0';
printf("\tw[%c]=%d\t\t\t",ptr->ch,ptr->weight);
for(index=0;code[index]!
='\0';index++)
printf("%c",code[index]);
printf("\n");;
ptr=tree;
index=0;
}
}
if(ptr->rchild&&ptr->rchild->mark==0)
{
ptr=ptr->rchild;
code[index++]='1';
}
if(!
ptr->lchild&&!
ptr->rchild)
{
ptr->mark=1;
code[index++]='\0';
printf("\tw[%c]=%d\t\t\t",ptr->ch,ptr->weight);
for(index=0;code[index]!
='\0';index++)
printf("%c",code[index]);
printf("\n");
ptr=tree;
index=0;
}
if(ptr->lchild->mark==1&&ptr->rchild->mark==1)
{
ptr->mark=1;
ptr=tree;
index=0;
}
}
}
printf("\n");
free(code);
}
4.4译码函数
以下函数是源程序中实现译码部分:
voiddecode(linktreetree,charcode[])
{
inti=0,j=0;
char*char0_1;
linktreeptr=tree;
char0_1=(char*)malloc(10*sizeof(char));/*此数组用于统计输入的0、1序列*/
printf("哈夫曼编码-----相应字符\n\n");
for(j=0,ptr=tree;code[i]!
='\0'&&ptr->lchild&&ptr->rchild;j=0,ptr=tree)
{
for(j=0;code[i]!
='\0'&&ptr->lchild&&ptr->rchild;j++,i++)
{if(code[i]=='0')
{ptr=ptr->lchild;
char0_1[j]='0';
}
if(code[i]=='1')
{
ptr=ptr->rchild;
char0_1[j]='1';
}
}
if(!
ptr->lchild&&!
ptr->rchild)
{
char0_1[j]='\0';
for(j=0;char0_1[j]!
='\0';j++)
printf("%c",char0_1[j]);
printf("%c",ptr->ch);
}
if(code[i]=='\0'&&ptr->lchild&&ptr->rchild)
{
char0_1[j]='\0';
printf("没有与最后的几个0、1序列:
%s相匹配的字符!
\n",char0_1);
return;
}
}
free(char0_1);
}
4.5运行结果
根据此次实验的设计需求及原理,我们编写出相应的源代码,在运行时可以得到相应的功能:
如下图的界面所示:
此界面中显示3种选择,可以分别执行不同的部分,由此看出,选择序号1可以进入编码界面,会提示输入字符串,按回车键即可输出与之对应哈夫曼编码。
图4.3编码界面
与之相对应的,下图则显示的是译码界面,即选择序号2时,根据提示,输入一串二进制数,即可编译成对应的字符:
图4.4译码界面
下图是打印出来的哈夫曼树的界面:
图4.5打印界面
5.调试分析
在我自己课程设计中,就在编写好源代码后的调试中出现了不少的错误,遇到了很多麻烦及困难,我的调试及其中的错误和我最终找出错误,修改为正确的能够执行的程序中,通过分析,我学到了:
(1)在定义头文件时可多不可少,即我们可多写些头文件,肯定不会出错,但是若没有定义所引用的相关头文件,必定调试不通过;
(2)在执行译码操作时,不知什么原因,总是不能把要编译的二进制数与编译成的字符用连接号连接起来,而是按顺序直接放在一起,视觉效果不是很好。
还有就是,很遗憾的是,我们的哈夫曼编码/译码器没有像老师要求的那样完成编一个文件的功能,这是我们设计的失败之处。
6.小结
通过本次数据结构的课程设计,我学习了很多之前上课没懂的知识。
并在冯珊老师指导下,我对求哈夫曼树及哈夫曼编码/译码的算法有了更加深刻的了解,更巩固了课堂中学习有关于哈夫曼编码的知识,真正学会一种算法了。
当求解一个算法时,不是拿到问题就不加思索地做,而是首先要先对它有个大概的了解,接着再详细地分析每一步怎么做,无论自己以前是否有处理过相似的问题,只要按照以上的步骤,必定会顺利地做出来。
这次课程设计中我在编辑方面犯了不应有的错误,设计统计字符和合并时忘记应该怎样保存保存数据,在老师的指导下明确并改正了错误和疏漏,使我们的程序有了更高的质量。
在上次的设计中已经积累了一些基本的经验,所以做起来相比上次算是顺利多了,但也还是会遇到一些这样或那样的问题,在这时就要看团体的力量,遇到困难时我们组会聚集到一块儿合力讨论,尽力把它解决,每次解决了一个问题之后就会给自己多了一份自信,对今后的学习和程序的设计有了更大的信心。
再次我更要真心的感谢冯珊老师对我们的帮助与指导。
我会更加努力学习数据结构方面的知识,来完善自己的学习。
这次课程设计,主要是对我们的c语言和数据结构的一次实际性应用,通过这次课程设计,来加强我们对c和数据结构的基本知识。
在这次设计中,我受益非浅。
开始设计时,我程序出现好多错误,经过仔细查找,我发现自己在c方面有好多语句不能正确应用。
开始我对文件不太会用,现在我这方面有了很大进步。
经过两个星期多的努力,我终于将课程设计做完了.在这次设计过程中,我遇到了许多编程问题,但在冯珊老师的辛勤指导下,同学的帮助和我的努力下,我顺利的完成了设计。
这次的课程设计让我受益非浅,发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固。
通过实践的学习,我认识到学好计算机要重视实践操作,不仅仅是学习语言,还是专业知识,都要重在实践,所以后在学习过程中,我会更加注视实践操作,使自己便好地学好本专业知识。
编写程序即是一件艰苦的工作,又是一件愉快的事情。
编程时如果遇到看似简单但又无法解决的问题,很容易灰心丧气。
此时切不可烦躁,一定要冷静的思考,认真的分析,其过程为:
面对问题,接受问题,处理问题,解决问题。
再次对给过我帮助的所有同学和各位指导老师表示忠心的感谢!
参考文献
[1]刘晓华.SQLServer2000数据库应用开发.北京:
电子工业出版社,2001.6
[2](美)微软公司著,王黎,袁永康译.Microsoft.NET战略.北京:
清华大学出版社,2002.1
[4]谭浩强.C程序设计第二版.北京:
清华大学出版社,2003
[5]任哲等.MFCWindows程序设计.北京:
清华大学出版社,2004
[6]唐克.MFC程序设计.北京:
北京希望电子出版社,2002
[7]严蔚敏,吴伟民.数据结构(C语言版).北京:
清华大学出版社,1997
[8]求是科技.VisualC++6.0信息管理系统开发.北京:
人民邮电出版社,2005
[9]朱晴婷,黄海鹰,陈莲君.VC++程序设计.北京:
清华大学出版社,1998
附录:
源程序代码
#include
#include
#include
#include
#include
//typedefintTElemType;
constintUINT_MAX=1000;
typedefstruct
{
intweight;
intparent,lchild,rchild;
}HTNode,*HuffmanTree;
typedefchar**HuffmanCode;
//-----------全局变量-----------------------
HuffmanTreeHT;
HuffmanCodeHC;
int*w,i,j,n;
char*z;
intflag=0;
intnumb=0;
//-----------------求赫夫曼编码-----------------------
intmin(HuffmanTreet,inti)
{//函数voidselect()调用
intj,flag;
intk=UINT_MAX;//取k为不小于可能的值
for(j=1;j<=i;j++)
if(t[j].weightk=t[j].weight,flag=j;
t[flag].parent=1;
returnflag;
}
//--------------------slect函数----------------------
voidselect(HuffmanTreet,inti,int&s1,int&s2)
{//s1为最小的两个值中序号小的那个
intj;
s1=min(t,i);
s2=min(t,i);
if(s1>s2)
{
j=s1;
s1=s2;
s2=j;
}
}
//--------------算法6.12--------------------------
voidHuffmanCoding(HuffmanTree&HT,HuffmanCode&HC,int*w,intn)
{//w存放n个字符的权值(均>0),构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC
intm,i,s1,s2,start;
//unsignedc,f;
intc,f;
HuffmanTreep;
char*cd;
if(n<=1)
return;//检测结点数是否可以构成树
m=2*n-1;
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//0号单元未用
for(p=HT+1,i=1;i<=n;++i,++p,++w)
{
p->weight=*w;
p->parent=0;
p->lchild=0;
p->rchild=0;
}
for(;i<=m;++i,++p)
p->parent=0;
for(i=n+1;i<=m;++i)//建赫夫曼树
{//在HT[1~i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2
select(HT,i-1,s1,s2);
HT[s1].parent=HT[s2].parent=i;
HT[i].lchild=s1;
HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
}
//从叶子到根逆向求每个字符的赫夫曼编码
HC=(HuffmanCode)malloc((n+1)*sizeof(char*));
//分配n个字符编码的头指针向量([0]不用)
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';
else
cd[--start]='1';
HC[i]=(char*)malloc((n-start)*sizeof(char));
//为第i个字符编码分配空间
strcpy(HC[i],&cd[start]);//从cd复制编码(串)到HC
}
free(cd);//释放工作空间
}
//--------------初始化赫夫曼链表---------------------------------
voidInitialization()
{
flag=1;
intnum;
intnum2;
cout<<"下面初始化赫夫曼链表"<";
cin>>num;
n=num;
w=(int*)malloc(n*sizeof(int));
z=(char*)malloc(n*sizeof(char));
cout<<"\n请依次输入"<必须以回车结束:
"<charbase[2];
for(i=0;i{
cout<<"第"<
"<gets(base);
*(z+i)=*base;
}
for(i=0;i<=n-1;i++)
{
cout<}
cout<<"\n请依次输入"<必须以回车结束):
"<for(i=0;i<=n-1;i++)
{
cout<";
cin>>num2;
*(w+i)=num2;
}
HuffmanCoding(HT,HC,w,n);
//--------------------打印编码-----------------------------------
cout<<"字符对应的编码为:
"<for(i=1;i<=n;i++)
{
//cout<<"字符"<<*(z+i-1)<<"的编码";
puts(HC[i]);
}
//--------------------------将赫夫曼编码写入文件------------------------
cout<<"下面将赫夫曼编码写入文件"<FILE*htmTree;
charr[]={'','\0'};
if((htmTree=fopen("htmTree.txt","w"))==NULL)
{
cout<<"cannotopenfile"<return;
}
fputs(z,htmTree);
for(i=0;i{
fprintf(htmTree,"%6d",*(w+i));
fputs(r,htmTree);
}
for(i=1;i<=n;i++)
{
fputs(HC[i],htmTree);
fputs(r,htmTree);
}
fclose(h