课程设计格式模板.docx
《课程设计格式模板.docx》由会员分享,可在线阅读,更多相关《课程设计格式模板.docx(12页珍藏版)》请在冰豆网上搜索。
![课程设计格式模板.docx](https://file1.bdocx.com/fileroot1/2022-11/21/1f6c8f8f-042e-4e96-8910-08936d01396b/1f6c8f8f-042e-4e96-8910-08936d01396b1.gif)
课程设计格式模板
计算机信息工程学院
《数据结构》
课程设计报告
题目:
哈夫曼编码
专业:
计算机科学与技术(软件方向)
班级:
15计算机软件二班
学号:
2015220140206
姓名:
郭琪
指导教师:
范智华
完成日期:
2016年6月24日
目录
摘要3
【关键词】3
哈夫曼编码4
一、需求分析4
二、哈夫曼树4
三、哈夫曼树的理论创建过程如下:
4
1、构成初始集合4
2、选取左右子树4
3、删除左右子树5
五、解码5
六、测试分析6
1、6
2、6
3、6
七、运行结果7
参考文献8
附 录9
致 谢14
摘要
在当今信息爆炸时代,如何采用有效的数据压缩技术来节省数据文件的存储空间和计算机网络的传送时间已越来越引起人们的重视。
电报通信是传递文字的二进制码形式的字符串。
但在信息传递时,总希望总长度尽可能最短,即采用最短码。
利用哈夫曼编码进行信息通信可以大大提高信道利用率,缩短信息传输的时间,减低传输成本。
但是,前提要求必须在发送端通过一个编码系统对准备传输的数据进行预先编码,而在接收端将传输来的数据进行译码。
本次实例要实现一个简单的哈夫曼编译器。
构造哈夫曼树时,首先将由n个字符形成的n个叶子结点存放到数组HTNode的前n个分量中,然后根据前文介绍的哈夫曼方法的基本思想,不断将两个小子树合并为一个较大的子树,每次构成的新子树的根结点顺序放到HTNode数组中的前n个分量的后面。
【关键词】
哈夫曼树;编码;解码;数据压缩技术;
哈夫曼编码
一、需求分析
利用哈夫曼编码进行通信可以大大提高信道的利用率,缩短信息传输的时间,降低传输成本。
根据哈夫曼编码的原理,编写一个程序,在用户输入结点权值的基础上求哈夫曼编码。
要求:
从键盘输入若干字符及每个字符出现的频率,将字符出现的频率作为结点的权值,建立哈夫曼树,然后对各个字符进行哈夫曼编码,最后打印输出字符及对应的哈夫曼编码。
二、哈夫曼树
哈夫曼树也称最优二叉树.给定一组具有确定权值的叶子结点,可以构造出不同的二叉树,将其中带权路径长度最小的二叉树称为哈夫曼树.其中,叶子结点的权值(weight)是对叶子结点赋予的一个有意义的数值量.设二叉树具有n个带权值的叶子结点,从根结点到各个叶子结点的路径长度与相应叶子结点权值的乘积之和叫做二叉树的带权路径长度(weightedpathlength),记为:
WPL=Wklk1nk,wk为第k个叶子结点的权值,lk为从根结点到第k个叶子结点的路径长度.
三、哈夫曼树的理论创建过程如下:
1、构成初始集合
对给定的n个权值{W1,W2,W3,...,Wi,...,Wn}构成n棵二叉树的初始集合F={T1,T2,T3,...,Ti,...,Tn},其中每棵二叉树Ti中只有一个权值为Wi的根结点,它的左右子树均为空。
2、选取左右子树
在F中选取两棵根结点权值最小的树作为新构造的二叉树的左右子树,新二叉树的根结点的权值为其左右子树的根结点的权值之和。
3、删除左右子树
从F中删除这两棵树,并把这棵新的二叉树同样以升序排列加入到集合F中。
4、重复二和三两步,
重复二和三两步,直到集合F中只有一棵二叉树为止。
四、编码
具体操作:
(1)从叶子结点开始按照所储存的夫结点的信息向上寻找,若该结点是夫结点的左孩子结点将路径记为0,是右孩子将路径记为1。
(2)用临时字符数组cd来存储路径并从后先前存储。
(3)从1找到的夫结点开始继续向上寻找,直到找到根结点,即parent=0结束。
五、解码
具体操作:
(1)以字符串的形式输入编码存于code中。
(2)从根结点开始编码所给的路径依次向下寻找。
(3)直到找到叶子结点为止。
(4)此时,若code=‘\0’,则译码结束,否则继续从根结点开始寻找。
六、测试分析
1、
感觉文件操作自己并不是很熟练,尽管在向显示器输出的时候并没有什么错误但是读写文件的时候就没那么顺利了,比如说当编写savewithhufcode函数时读文件,却总不执行,后来通过断点测试发现每次fgetc()返回值总为-1,于是我考虑是否是文件没有打开或者文件结束的缘故,后来想通了是之前打开的文件光标读操作结束后仍在结尾故每次总返回-1,故调用rewind函数将光标位置移动到文章开始。
2、
用哈夫曼编码存储文件的时候还应注意数字0,1与字符0,1的不同,不应直接在fputc()函数中直接写入0,1那么将会是写入的文章中什么都没有,因为0在ASCII码中代表NULL。
3、
该程序函数清晰功能明确,程序具有通用性,对于不同的输入文章都可进行处理,由于采用哈夫曼编码对照表,使得查看哈夫曼编码是效率较高无需每次遍历哈夫曼树。
七、运行结果
参考文献
[1]孙家广,杨长青.计算机图形学[M].北京:
清华大学出版社,1995.26~28
[2]SkolinkMI.RadarHandbook[M].NewYork:
McGraw-Hill,1990
[3]李旭东,宗光华,毕树生等.生物工程微操作机器人视觉系统的研究
[4]王明亮.关于中国学术期刊标准化数据系统工程的进展[EB/OL].http:
//www.cajcd.edu.cn/pub/wm1.txt/980810-2.html,1998-08-16/1998-10-04
[5]严蔚敏,数据结构(C语言版),清华大学出版社,2007
[6]郑莉,C++语言程序设计(第4版),清华大学出版社,2010
[7]谭浩强,C程序设计(第三版),清华大学出版社,2005
附 录
#include
#include
#include
#include
typedefstruct{
chardata;
intweight;
intparent,lchild,rchild;
}HTNode,*HuffmanTree;
typedefchar**HuffmanCode;
voidSelect(HuffmanTree&HT,intn,intm)
{HuffmanTreep=HT;
inttmp;
for(intj=n+1;j<=m;j++)
{inttag1,tag2,s1,s2;
tag1=tag2=32767;
for(intx=1;x<=j-1;x++)
{if(p[x].parent==0&&p[x].weight{tag1=p[x].weight;s1=x;}
}
for(inty=1;y<=j-1;y++)
{if(p[y].parent==0&&y!
=s1&&p[y].weight{tag2=p[y].weight;s2=y;}
}
if(s1>s2)//将选出的两个节点中的序号较小的始终赋给s1
{tmp=s1;s1=s2;s2=tmp;}
p[s1].parent=j;
p[s2].parent=j;
p[j].lchild=s1;
p[j].rchild=s2;
p[j].weight=p[s1].weight+p[s2].weight;
}
}
voidHuffmanCoding(HuffmanTree&HT,intn,char*w1,int*w2)
{
intm=2*n-1;
if(n<=1)return;
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
HuffmanTreep=HT;
for(inti=1;i<=n;i++)
{p[i].data=w1[i-1];
p[i].weight=w2[i];
p[i].parent=p[i].lchild=p[i].rchild=0;
}
for(;i<=m;i++)
{p[i].weight=p[i].parent=p[i].lchild=p[i].rchild=0;}
Select(HT,n,m);
ofstreamoutfile;//生成hfmTree文件
outfile.open("hfmTree.txt",ios:
:
out);
for(i=1;i<=m;i++)
{outfile<<<"\t"<}
outfile.close();
cout<<"初始化结果已保存在hfmTree文件中\n";
}
voidToBeTree()//将正文写入文件ToBeTree中
{
ofstreamoutfile;
outfile.open("ToBeTree.txt",ios:
:
out);
outfile<<"THISPROGRAMISMYFAVORITE";
outfile.close();
}
voidEncoding(HuffmanTree&HT,intn)//编码
{
HuffmanCodeHC;
HC=(HuffmanCode)malloc((n+1)*sizeof(char*));
char*cd;
cd=(char*)malloc(n*sizeof(char));
cd[n-1]='\0';
for(intk=1;k<=n;k++)
{intstart=n-1;
for(intc=k,f=HT[k].parent;f!
=0;c=f,f=HT[f].parent)
{if(HT[f].lchild==c)cd[--start]='0';
elsecd[--start]='1';
}
HC[k]=(char*)malloc((n-start)*sizeof(char));
strcpy(HC[k],&cd[start]);
}
cout<<"输出哈夫曼编码:
"<for(inth=1;h<=n;h++)//输出编码
{cout<";
cout<cout<<"";
if(h%8==0)cout<}
cout<"<ToBeTree();
//读取TOBETREE文件里的正文,并进行编码
fstreaminfile;
infile.open("ToBeTree.txt",ios:
:
in);
chars[80];
while(!
infile.eof())
{infile.getline(s,sizeof(s));}
infile.close();
fstreamoutfile;
outfile.open("CodeFile.txt",ios:
:
out);
intcount=0;
for(h=0;s[h]!
='\0';h++)
{for(k=1;k<=n;k++)
if(s[h]==HT[k].data)
{cout<cout<<"";
count++;
outfile<break;
}
if(count%9==0)cout<}
outfile.close();
cout<<"\n编码结果已保存在文件CodeFile中.";
cout<}
voidDecoding(HuffmanTree&HT,intn)//译码
{
intf=2*n-1;
fstreaminfile;
infile.open("CodeFile.txt",ios:
:
in);
chars[1000];
while(!
infile.eof())
{infile.getline(s,sizeof(s));}
infile.close();
inti=0;
intj=0;
fstreamoutfile;
outfile.open("TextFile.txt",ios:
:
out);
while(s[i]!
='\0')
{f=2*n-1;
while(HT[f].lchild!
=0)//以f对应的节点的左孩子的值==0作为结束
{if(s[j]=='0')f=HT[f].lchild;
elsef=HT[f].rchild;
j++;
}
i=j;
cout<outfile<}
outfile.close();
cout<<"\n译码结果已保存在文件TextFile中.";
cout<}
voidPrint()//印代码文件
{intcount=0;
fstreaminfile;
infile.open("CodeFile.txt",ios:
:
in);
chars[1000];
while(!
infile.eof())
{infile.getline(s,sizeof(s));
for(inti=0;s[i]!
='\0';i++)
{cout<
count++;
if(count%50==0)cout<}
}
infile.close();
cout<}
charmenu()//菜单函数
{cout<<"功能菜单如下:
"<cout<<"*********************"<cout<<"I:
初始化(Initialization)"<cout<<"E:
编码(Encoding)"<cout<<"D:
译码(Decoding)"<cout<<"P:
打印编码(Print)"<cout<<"Q:
退出(Exit)"<cout<<"*********************"<cout<<"请输入功能字符:
";
charch;
cin>>ch;
returnch;
}
voidmain()
{intn;
intArray[100];
charcArray[100];
HuffmanTreeHT;
cout<<"输入n个字符:
";
cin.getline(cArray,100);
n=strlen(cArray);
cout<<"一共"<cout<<"依次输入各个字符的权值:
"<for(inti=1;i<=n;i++)cin>>Array[i];
inttag;
charx=menu();
while
(1)
{switch(x)
{
case'I':
HuffmanCoding(HT,n,cArray,Array);break;
case'E':
Encoding(HT,n);break;
case'D':
Decoding(HT,n);break;
case'P':
Print();break;
case'Q':
tag=0;cout<<"结束"<default:
cout<<"你输入错误!
"<if(tag==0)break;
cout<<"y(继续)orn(退出)"<charch;
cin>>ch;
if(ch=='y')
{cout<<"请输入功能字符:
";
charc;
cin>>c;
x=c;}
elseexit
(1);
}
}
致 谢
在本次课程设计的整个过程中,要特别感谢自始至终给我提供帮助和指导的范智华老师,是他耐心的指导才使得本次设计得以顺得完成,同时,也要感谢小组成员的不懈努力和互相配合,在此还要特别感谢为我们提供良好上机环境的学校.如果没有以上老师,同学和学校的帮助和支持,本次设计实难完成.再次感谢老师的精心辅导和同学的相互帮助,使我们顺利完成此次设计以及为学习以后的科目打下良好的基础.
课程设计总结:
本次哈夫曼编码译码器的课程实验做得还算成功,不仅仅在于程序能够正常运行,实现应有的功能,关键在于过程,在于小组成员的分工合作和一起纠错排错的过程,在完成程序的过程中才能真正理解面向对象和模块化设计的思想,我们不仅仅是说要每人分几个函数,关键在于这些函数代表的是一个个功能模块,任何一个模块出现问题或者模块之间的衔接出现问题都将导致程序运行的失败。
初始的创建是哈夫曼编码译码系统成功的关键,我在创建的过程当中多次使用树的先根,配合中根遍历操作,输出接点字符或者权重信息,作为检验,对验证和纠错起到了非常大的作用。
在适当的地方调用它们,运行时可以看到验证编写程序的正确性;
通过本次实验,提高了自已调试程序的能力。
充分体会到了在程序执行时的提示性输出的重要性。
编写大一点的程序,应先写出算法,再写程序,一段一段调试;对于没有实现的操作用空操作代替,这样容易找出错误所在。
最忌讳将所有代码写完后再调试,这样若程序有错误,太难找。
1、编码不熟练,经常出现漏符号或多符号,多次调试改正
2、C++不熟练,读取保存文件出错,回归课本,改正代码
指导教师评语:
指导教师(签字):
年月日
课程设计成绩