课程设计郝显文2.docx
《课程设计郝显文2.docx》由会员分享,可在线阅读,更多相关《课程设计郝显文2.docx(28页珍藏版)》请在冰豆网上搜索。
课程设计郝显文2
目录
内蒙古科技大学课程设计任务书I
第一节需求分析1
1.1引言1
1.2任务概述1
1.3数据描述2
第二章设计概要3
2.1总体设计3
2.2数据类型4
第三章详细设计6
3.1主函数6
3.2存储表示6
3.3赫夫曼树的算法7
3.5赫夫曼译码的算法10
3.6显示界面源程序12
第四章测试及运行14
4.1运行结果14
4.2测试分析16
第五章总结17
5.1心得体会17
5.2参考文献17
附录:
程序代码18
内蒙古科技大学
本科生课程设计论文
题目:
Huffman编码和译码
学生姓名:
郝显文
学号:
1176807316
专业:
计算机科学与技术
班级:
3
指导教师:
丁雨
2013年05月27日
内蒙古科技大学课程设计任务书
课程名称
数据结构课程设计
设计题目
Huffman编码和译码
指导教师
丁雨
时间
2013.5.20——2013.5.30
一、教学要求
1.掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力
2.初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能
3.提高综合运用所学的理论知识和方法独立分析和解决问题的能力
4.训练用系统的观点和软件开发一般规范进行软件开发,培养软件工作者所应具备的科学的工作方法和作风
二、设计资料及参数
每个学生在教师提供的课程设计题目中任意选择一题,独立完成,题目选定后不可更换。
Huffman编码和译码
根据给定的字符集和各字符的频率值,求出其中给定字符Huffman编码,并针对一段文本(定义在该字符集上)进行编码和译码,实现一个Huffman编码/译码系统。
要求设计类(或类模板)来描述Huffman树及其操作,包含必要的构造函数和析构函数,以及其他能够完成如下功能的成员函数:
v求Huffman编码
v输入字符串,求出编码
v输入一段编码,实现译码
并设计主函数测试该类。
三、设计要求及成果
1.分析课程设计题目的要求
2.写出详细设计说明
3.编写程序代码,调试程序使其能正确运行
4.设计完成的软件要便于操作和使用
5.设计完成后提交课程设计报告
四、进度安排
资料查阅与讨论(1天)
系统分析(2天)
系统的开发与测试(5天)
编写课程设计说明书和验收(2天)
五、评分标准
1.根据平时上机考勤、表现和进度,教师将每天点名和检查
2.根据课程设计完成情况,必须有可运行的软件。
3.根据课程设计报告的质量,如有雷同,则所有雷同的所有人均判为不及格。
4.根据答辩的情况,应能够以清晰的思路和准确、简练的语言叙述自己的设计和回答教师的提问
六、建议参考资料
1.《数据结构(C语言版)》严蔚敏、吴伟民主编清华大学出版社2004.11
2.《数据结构课程设计案例精编(用C/C++描述)》,李建学等编著,清华大学出版社2007.2
3.《数据结构:
用面向对象方法与C++语言描述》,殷人昆主编, 清华大学出版社2007
第一节需求分析
1.1引言
在当今信息爆炸时代,如何采用有效的数据压缩技术节省数据文件的存储空间和计算机网络的传送时间已越来越引起人们的重视,赫夫曼编码正是一种应用广泛且非常有效的数据压缩技术。
Huffman编码是一种编码方式,以Huffman树—即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。
哈弗曼编码使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。
这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目的)。
赫夫曼编码的应用很广泛,利用赫夫曼树求得的用于通信的二进制编码称为赫夫曼编码。
树中从根到每个叶子都有一条路径,对路径上的各分支约定:
指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为和各个叶子对应的字符的编码,这就是Huffman编码。
Huffman译码输入字符串可以把它编译成二进制代码,输入二进制代码时可以编译成字符串。
1.2任务概述
Huffman编码和译码:
根据给定的字符集和各字符的频率值,求出其中给定字符Huffman编码,并针对一段文(定义在该字符集上)进行编码和译码,实现一个Huffman编码/译码系统。
要求设计类(或类模板)来描述Huffman树及其操作,包含必要的构造函数和析构函数,以及其他能够完成如下功能的成员函数:
①求Huffman编码。
②输入字符串,求出编码。
③输入一段编码,实现译码。
④并设计主函数测试该类。
1.3数据描述
①给定的字符频率表
字符
A
B
C
D
E
F
G
H
I
J
K
L
M
频度
186
64
13
22
32
103
21
15
47
57
1
2
32
字符
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
频度
20
57
63
15
1
48
51
80
23
8
18
1
16
表1.1
②测试的字符
测试的编码:
haoxianwen测试的译码:
10110101111000
第二章设计概要
2.1总体设计
①赫夫曼树的建立
赫夫曼树的建立由赫夫曼算法的定义可知,初始森林中共有n棵只含有根结点的二叉树。
算法的第二步是:
将当前森林中的两棵根结点权值最小的二叉树,合并成一棵新的二叉树;每合并一次,森林中就减少一棵树,产生一个新结点。
显然要进行n-1次合并,所以共产生n-1个新结点,它们都是具有两个孩子的分支结点。
由此可知,最终求得的赫夫曼树中一共有2n-1个结点,其中n个结点是初始森林的n个孤立结点。
并且赫夫曼树中没有度数为1的分支结点。
我们可以利用一个大小为2n--1的一维数组来存储赫夫曼树中的结点。
②赫夫曼编码
要求电文的赫夫曼编码,必须先定义赫夫曼编码类型,根据设计要求和实际需要定义的类型如下:
typedetstruct{
charch;//存放编码的字符
charbits[N+1];//存放编码位串
intlen;//编码的长度
}CodeNode;//编码结构体类型
③代码文件的译码
译码的基本思想是:
读文件中编码,并与原先生成的赫夫曼编码表比较,遇到相等时,即取出其对应的字符存入一个新串中。
2.2数据类型
①主要的数据结构:
#defineN50//叶子结点数
#defineM2*N-1//赫夫曼树中结点总数
typedefstruct{
intweight;//叶子结点的权值
intlchild,rchild,parent;//左右孩子及双亲指针
}HTNode;//动态分配数组存储赫夫曼树
typedefHTNodeHuffmanTree[M+1];
②主要流程图
图2.1
第三章详细设计
3.1主函数
voidmain()
{
intn=26,i;
charorz,back,flag=1;
charstr[]={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};//初始化
intfnum[]={186,64,13,22,32,103,21,15,47,57,1,2,32,20,57,63,15,1,48,51,80,23,8,18,1,16};//初始化
HTNodeht[M];//建立结构体
HCodehcd[N];//建立结构体
for(i=0;i{
ht[i].data=str[i];
ht[i].weight=fnum[i];
}
while(flag)//菜单函数,当flag为0时跳出循环
3.2存储表示
typedefstruct{
intweight;//叶子结点的权值
intlchild,rchild,parent;//左右孩子及双亲指针
}HTNode;//树中结点类型
typedefHTNodeHuffmanTree[M+1];
3.3赫夫曼树的算法
voidCreateHT(HTNodeht[],intn)//调用输入的数组ht[],和节点数n
{
inti,k,lnode,rnode;
intmin1,min2;
for(i=0;i<2*n-1;i++)
ht[i].parent=ht[i].lchild=ht[i].rchild=-1;//所有结点的相关域置初值-1
for(i=n;i<2*n-1;i++)//构造哈夫曼树
{
min1=min2=32767;//int的范围是-32768—32767
lnode=rnode=-1;//lnode和rnode记录最小权值的两个结点位置
for(k=0;k<=i-1;k++)
{
if(ht[k].parent==-1)//只在尚未构造二叉树的结点中查找
{
if(ht[k].weight{
min2=min1;rnode=lnode;
min1=ht[k].weight;lnode=k;
}
elseif(ht[k].weight{
min2=ht[k].weight;rnode=k;
}
}
}
ht[lnode].parent=i;ht[rnode].parent=i;//两个最小节点的父节点是i
ht[i].weight=ht[lnode].weight+ht[rnode].weight;//两个最小节点的父节点权值为两个最小节点权值之和
ht[i].lchild=lnode;ht[i].rchild=rnode;//父节点的左节点和右节点
}
}
3.4赫夫曼编码的算法
voidCreateHCode(HTNodeht[],HCodehcd[],intn)
{
inti,f,c;
HCodehc;
for(i=0;i{
hc.start=n;c=i;
f=ht[i].parent;
while(f!
=-1)//循序直到树根结点结束循环
{
if(ht[f].lchild==c)//处理左孩子结点
hc.cd[hc.start--]='0';
else//处理右孩子结点
hc.cd[hc.start--]='1';
c=f;f=ht[f].parent;
}
hc.start++;//start指向哈夫曼编码hc.cd[]中最开始字符
hcd[i]=hc;
}
}
voidDispHCode(HTNodeht[],HCodehcd[],intn)//输出哈夫曼编码的列表
{
inti,k;
printf("输出哈夫曼编码:
\n");
for(i=0;i{
printf("%c:
\t",ht[i].data);
for(k=hcd[i].start;k<=n;k++)//输出所有data中数据的编码
{
printf("%c",hcd[i].cd[k]);
}
printf("\n");
}
}
voideditHCode(HTNodeht[],HCodehcd[],intn)//编码函数
{
charstring[MAXSIZE];
inti,j,k;
scanf("%s",string);//把要进行编码的字符串存入string数组中
printf("\n输出编码结果:
\n");
for(i=0;string[i]!
='#';i++)//#为终止标志
{
for(j=0;j{
if(string[i]==ht[j].data)//循环查找与输入字符相同的编号,相同的就输出这个字符的编码
{
for(k=hcd[j].start;k<=n;k++)
{
printf("%c",hcd[j].cd[k]);
}
break;//输出完成后跳出当前for循环
}
}
}
}
3.5赫夫曼译码的算法
voiddeHCode(HTNodeht[],HCodehcd[],intn)//译码函数
{
charcode[MAXSIZE];
inti,j,l,k,m,x;
scanf("%s",code);//把要进行译码的字符串存入code数组中
while(code[0]!
='#')
for(i=0;i{
m=0;//m为想同编码个数的计数器
for(k=hcd[i].start,j=0;k<=n;k++,j++)//j为记录所存储这个字符的编码个数
{
if(code[j]==hcd[i].cd[k])//当有相同编码时m值加1
m++;
}
if(m==j)//当输入的字符串与所存储的编码字符串个数相等时则输出这个的data数据
{
printf("%c",ht[i].data);
for(x=0;code[x-1]!
='#';x++)//把已经使用过的code数组里的字符串删除
{
code[x]=code[x+j];
}
}
}
}
3.6显示界面源程序
{
printf("\n");
printf("********************************");
printf("\n**1---------------显示编码**");
printf("\n**2---------------进行编码**");
printf("\n**3---------------进行译码**");
printf("\n**4---------------退出**\n");
printf("***********************************");
printf("\n");
printf("请输入选择的编号:
");
scanf("%c",&orz);
switch(orz)
{
case'a':
case'A':
system("cls");//清屏函数
CreateHT(ht,n);
CreateHCode(ht,hcd,n);
DispHCode(ht,hcd,n);
printf("\n按任意键返回...");
getch();
system("cls");
break;
case'b':
case'B':
system("cls");
printf("请输入要进行编码的字符串(以#结束):
\n");
editHCode(ht,hcd,n);
printf("\n按任意键返回...");
getch();
system("cls");
break;
case'c':
case'C':
system("cls");
DispHCode(ht,hcd,n);
printf("请输入编码(以#结束):
\n");
deHCode(ht,hcd,n);
printf("\n按任意键返回...");
getch();
system("cls");
break;
case'd':
case'D':
flag=0;
break;
default:
system("cls");
}
}
第四章测试及运行
4.1运行结果
主界面
图4.1
Huffman编码
图4.2
编码界面
图4.3
译码界面
图4.4
4.2测试分析
整个程序代码是分块书写的,在建立Huffman树函数时花费时间较多,其余的部分比较顺利。
虽然其他函数在调试过程中或多或少都出现了问题,但都是一些细节问题经过细心的检查就都改正了。
第五章总结
5.1心得体会
通过这次课程设计,让我对一个程序的数据结构有更全面更进一步的认识,根据不同的需求,采用不同的数据存储方式,不一定要用栈,二叉树等高级类型,有时用基本的一维数组,只要运用得当,也能达到相同的效果,甚至更佳,就如这次的课程设计,通过用for的多重循环,舍弃多余的循环,提高了程序的运行效率。
在编写这个程序的过程中,我复习了之前学的基本语法,哈弗曼树最小路径的求取,哈弗曼编码及译码的应用范围,程序结构算法等一系列的问题它使我对数据结构改变了看法。
在这次设计过程中,体现出自己单独设计模具的能力以及综合运用知识的能力,体会了学以致用、突出自己劳动成果的喜悦心情,也从中发现自己平时学习的不足和薄弱环节,从而加以弥补。
5.2参考文献
《数据结构(C语言版)》严蔚敏、吴伟民主编清华大学出版社2004.11
《数据结构课程设计案例精编(用C/C++描述)》,李建学等编著,清华大学出版社2007.2
《数据结构:
用面向对象方法与C++语言描述》,殷人昆主编, 清华大学出版社2007
附录:
程序代码
#include
#include//要用system函数要调用的头文件
#include//用getch()要调用的头文件
#include
#defineN50//义用N表示50叶节点数
#defineM2*N-1//用M表示节点总数当叶节点数位n时总节点数为2n-1
#defineMAXSIZE100
typedefstruct
{
chardata;//结点值
intweight;//权值
intparent;//双亲结点
intlchild;//左孩子结点
intrchild;//右孩子结点
}HTNode;
typedefstruct
{
charcd[N];//存放哈夫曼码
intstart;//从start开始读cd中的哈夫曼码
}HCode;
voidCreateHT(HTNodeht[],intn)//调用输入的数组ht[],和节点数n
{
inti,k,lnode,rnode;
intmin1,min2;
for(i=0;i<2*n-1;i++)
ht[i].parent=ht[i].lchild=ht[i].rchild=-1;//所有结点的相关域置初值-1
for(i=n;i<2*n-1;i++)//构造哈夫曼树
{
min1=min2=32767;//int的范围是-32768—32767
lnode=rnode=-1;//lnode和rnode记录最小权值的两个结点位置
for(k=0;k<=i-1;k++)
{
if(ht[k].parent==-1)//只在尚未构造二叉树的结点中查找
{
if(ht[k].weight{
min2=min1;rnode=lnode;
min1=ht[k].weight;lnode=k;
}
elseif(ht[k].weight{
min2=ht[k].weight;rnode=k;
}
}
}
ht[lnode].parent=i;ht[rnode].parent=i;//两个最小节点的父节点是i
ht[i].weight=ht[lnode].weight+ht[rnode].weight;//两个最小节点的父节点权值为两个最小节点权值之和
ht[i].lchild=lnode;ht[i].rchild=rnode;//父节点的左节点和右节点
}
}
voidCreateHCode(HTNodeht[],HCodehcd[],intn)
{
inti,f,c;
HCodehc;
for(i=0;i{
hc.start=n;c=i;
f=ht[i].parent;
while(f!
=-1)//循序直到树根结点结束循环
{
if(ht[f].lchild==c)//处理左孩子结点
hc.cd[hc.start--]='0';
else//处理右孩子结点
hc.cd[hc.start--]='1';
c=f;f=ht[f].parent;
}
hc.start++;//start指向哈夫曼编码hc.cd[]中最开始字符
hcd[i]=hc;
}
}
voidDispHCode(HTNodeht[],HCodehcd[],intn)//输出哈夫曼编码的列表
{
inti,k;
printf("输出哈夫曼编码:
\n");
for(i=0;i{
printf("%c:
\t",ht[i].data);
for(k=hcd[i].start;k<=n;k++)//输出所有data中数据的编码
{
printf("%c",hcd[i].cd[k]);
}
printf("\n");
}
}
voideditHCode(HTNodeht[],HCodehcd[],intn)//编码函数
{
charstring[MAXSIZE];
inti,j,k;
scanf("%s",string);//把要进行编码的字符串存入string数组中
printf("\n输出编码结果:
\n");
for(i=0;string[i]!
='