数据结构课程设计
报告
软件系统测试报告下载sgs报告如何下载关于路面塌陷情况报告535n,sgs报告怎么下载竣工报告下载
-哈夫曼编码译码器系统
数据结构 课程设计报告
课
题
快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题
:
061班 专业班级: 信 息
学 号: 200616020208
姓 名:
指导教师:
评阅意见:
评定成绩:
指导老师签名: 目 录
年 月 日
目 录
目录 ................................................................................................. 1 1 课程设计的目的和意义 .............................................................. 2 2 需求分析 ...................................................................................... 3 3 系统(项目)设计 ...................................................................... 5
?设计思路及方案………………………………………………5
?模块的设计及介绍……………………………………………5
?主要模块程序流程图…………………………………………8
4 系统实现 .................................................................................... 11
?主调函数…………..…………………………..……………..12
?建立HuffmanTree……………………………………………12
?生成Huffman编码并写入文件……………………………..15
?电文译码……………………………………………………..16
5 系统调试 .................................................................................... 17 参考文献........................................................................................ 20 附录 源程序 .................................................................................. 21
1
1课程设计的目的和意义
在当今信息爆炸时代,如何采用有效的数据压缩技术来节省数据文件的存储空间和计算机网络的传送时间已越来越引起人们的重视。哈夫曼编码正是一种应用广泛且非常有效的数据压缩技术。
哈夫曼编码的应用很广泛,利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。树中从根到每个叶子都有一条路径,对路径上的各分支约定:指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为和各个对应的字符的编码,这就是哈夫曼编码。
通常我们把数据压缩的过程称为编码,解压缩的过程称为解码。电报通信是传递文字的二进制码形式的字符串。但在信息传递时,总希望总长度尽可能最短,即采用最短码。
作为信息管理专实践的机会~课程设计就是为解决这个问题提供了一个平台。
在课程设计过程中,我们每个人选择一个课题,认真研究,根据课堂讲授内容,借助书本,自己动手实践。这样不但有助于我们消化课堂所讲解的内容,还可以增强我们的独立思考能力和动手能力;通过编写实验代码和调试运行,我们可以逐步积累调试C程序的经验并逐渐培养我们的编程能力、用计算机解决实际问题的能力。
在课程设计过程中,我们不但有自己的独立思考,还借助各种参考文献来帮助我们完成系统。更为重要的是,我们同学之间加强了交流,在对问题的认识方面可以交换不同的意见。同时,师生之间的互动也随之改善,我们可以通过具体的实例来从老师那学到更多的实用的知识。
数据结构课程具有比较强的理论性,同时也具有较强的可应用性和实践性。课程设计是一个重要的教学环节。我们在一般情况下都能够重视实验环节,但是容易忽略实验的总结,忽略实验报告的撰写。通过这次实验让我们明白:作为一名大学生必须严格训练分析总结能力、书面表达能力。需要逐步培养书写科学实验报告以及科技论文的能力。只有这样,我们的综合素质才会有好的提高。
2
2需求分析
课 题:哈夫曼编码译码器系统
问题描述:打开一篇英文文章,统计该文章中每个字符出现的次数,然后以它们
作为权值,对每一个字符进行编码,编码完成后再对其编码进行译码。 问题补充:1. 从硬盘的一个文件里读出一段英
语文
八上语文短文两篇二年级语文一匹出色的马课件部编版八上语文文学常识部编八上语文文学常识二年级语文一匹出色的马课件
章;
2. 统计这篇文章中的每个字符出现的次数;
3. 以字符出现字数作为权值,构建哈夫曼树,并将哈夫曼树的存储
结构的初态和终态进行输出;
4. 对每个字符进行编码并将所编码写入文件然后对所编码进行破
译。
具体介绍:在本课题中,我们在硬盘E盘中预先建立一个file1.txt文档,在里面
编辑一篇文章(大写)。然后运行程序,调用fileopen()函数读出该文章,
显示在界面;再调用jsq()函数对该文章的字符种类进行统计,并对每
个字符的出现次数进行统计,并且在界面上显示;然后以每个字符出
现次数作为权值,调用ChuffmanTree()函数构建哈夫曼树;并调用
print1()和print2()函数将哈夫曼的存储结构的初态和终态进行输出。
然后调用HuffmanEncoding()函数对哈夫曼树进行编码,调用coding()
函数将编码写入文件;再调用decode()对编码进行译码,再输出至界
面。至此,整个工作就完成了。
测试数据:例如从文本中读到文章为:IAMASTUDENT。
则效果如下:
IAMASTUDENT
--------------------------------------
HuffmanTree的初态:
2 0 0 0
1 0 0 0
1 0 0 0
1 0 0 0
1 0 0 0
1 0 0 0
1 0 0 0
2 0 0 0
1 0 0 0
3
- 0 0 0
- 0 0 0
- 0 0 0
- 0 0 0
- 0 0 0
- 0 0 0
- 0 0 0
0 0 0 -
--------------------------------------
字符A次数:2
字符D次数:1
字符E次数:1
字符I 次数:1
字符M次数:1
字符N 次数:1
字符S 次数:1
字符T次数:2
:1 字符U次数
--------------------------------------
HuffmanTree的终态:
2 13 0 0
1 10 0 0
1 10 0 0
1 11 0 0
1 11 0 0
1 12 0 0
1 12 0 0
2 14 0 0
1 13 0 0
2 14 2 3
2 15 4 5
2 15 6 7
3 16 9 1
4 16 8 10
4 17 11 12
7 17 13 14
11 0 15 16 --------------------------------------
译码后的字符串:
IAMASTUDENT
**********************************************************
Press any key to continue
4
3 系统(项目)设计
(1)设计思路及方案
本课题是用最优二叉树即哈夫曼树来实现哈夫曼编码译码器的功能。假设每种字符在电文中出现的次数为Wi,编码长度为Li,电文中有n种字符,则电文编码总长度为(W1*L1)+(W2*L2)+„+(Wi*Li)。若将此对应到二叉树上,Wi为叶结点,Li为根结点到叶结点的路径长度。那么,(W1*L1)+(W2*L2)+„+(Wi*Li)恰好为二叉树上带权路径长度。
因此,设计电文总长最短的二进制前缀编码,就是以n种字符出现的频率作权,构造一棵哈夫曼树,此构造过程称为哈夫曼编码。
该系统将实现以下几大功能:从硬盘读取字符串,建立哈夫曼树,输出哈夫曼树的存储结构的初态和终态,输出各种字符出现的次数以及哈夫曼编码的译码等。
(2)模块的设计及介绍
?从硬盘读取字符串
fileopen(参数)
{
实现命令;
打印输出;
}
?建立HuffmanTree
通过三个函数来实现:
void select(参数)
{
初始化;
for
{
接受命令;
处理命令;
}
5
}
说明:在ht[1....k]中选择parent为0且权值最小的两个根结点的算法
int jsq(参数)
{
初始化;
for
{
接受命令;
处理命令;
}
}
说明:统计字符串中各种字母的个数以及字符的种类
void ChuffmanTree() {
初始化;
for
{
接受命令;
处理命令;
}
输出字符统计情况;
}
说明:构造哈夫曼树
?输出哈夫曼树的存储结构的初态和终态 分别调用print1()和print2()来实现 void print1(参数)
{
初始化;
输出初态;
6
}
说明:输出哈夫曼树的初态
void print2(参数) {
for
{
输出终态;
}
}
说明:输出哈夫曼树的终态
?哈夫曼编码和译码 void HuffmanEncoding(参数)
{
定义变量;
{
处理命令;
}
}
说明:哈夫曼编码 char*decode(参数) {
定义变量;
while
{
接受命令;
处理命令;
}
}
说明:哈夫曼译码
7
(3)主要模块程序流程图
下面介绍三个主要的程序模块流程图:
?主函数流程图:
开始
否 打开文件,
是
字符总数num
统计字符种类及频率
建立哈夫曼树
哈夫曼编码
哈夫曼译码
结束
图3.1
流程图注释:
该图比较简单,主要是调用各个函数模块,首先代开已经存在的文件,然后统计
总的字符数以及出现的各个字符和频率。然后才开始建立哈夫曼树,接着在哈夫
曼树的基础上对其进行编码,编码之后才是译码。最后输出结束。
8
?构造哈夫曼树:
开始
第i个结点权值
否 i=num?
是
第i个根结点
否 i=2*num-1?
是
创建哈夫曼树
输出字符统计情况
否 i=num?
是
结束
图3.2 流程图注释:
该图是表示构造哈夫曼树的过程。首先输入num个叶结点的权值,当i=num是循
环结束。然后进行哈夫曼树的构建,当i=2*num-1是循环结束。最后输出所得到
的字符统计情况。
9
?哈夫曼编码:
开始
Cd[--start]=0,start=num
T[p].lchlid=c?
是 否
Cd[--start]=0 Cd[--start]=1
是 i<=num?
否
结束
图3.3
流程图解释:
该流程图表四哈夫曼编码情况。首先初始化,Cd[--start]=0,start=num。然后进行 编码,使用了一个三目运算符。cd[--start]=(T[p].lchild==c) ? '0' : '1',即当cd[--start]=T[p].lchild= =c时,cd[--start]=0;当cd[--start]=T[p].lchild~= =c时,cd[--start]=1。这个编码循环一直到i=num时结束。
10
4 系统实现
各模块关键代码及算法的解释:
? 主调函数
代码解释:这是main函数里的各个函数调用情况。
fileopen(string); //从硬盘中读取文件
num=jsq(string,cnt,str); //统计字符种类及各类字符出现的频率
DhuffmanTree(HT,cnt,str);
\n"); printf("HuffmanTree的初态:
print1(HT); //输出哈夫曼树的初态
ChuffmanTree(HT,HC,cnt,str);//建立哈夫曼树
HuffmanEncoding(HT,HC); //生成哈夫曼编码
printf("HuffmanTree的终态:\n");
print2(HT); //输出哈夫曼树的终态
s=decode(HC); //读编码文件译码
printf("译码后的字符串:\n");
printf("%s\n",s); //输出译码后的字符串 ? 建立HuffmanTree
代码解释:该函数为在ht[1....k]中选择parent为0且权值最小的两个根结点的算法,其序号为s1和s2。
void select(HuffmanTree T,int k,int &s1,int &s2)
{
int i,j;
int min1=101;
for(i=1;i<=k;i++)
if(T[i].weight
='A'&&*p<='Z')
k=*p-64;
temp[k]++;
}
} //统计各种字符的个数
for(i=1,j=0;i<=26;++i)
if(temp[i]!=0 )
{
j++;
12
str[j]=i+64; //送对应的字母到数组中
cnt[j]=temp[i]; //存入对应字母的权值
}
return j; //j是输入字母总数
}
代码解释:下面函数用来构造哈夫曼树HT。首先初始化哈夫曼树,然后输入前面统计的各结点的权值,用for循环来构造哈夫曼树。 void ChuffmanTree(HuffmanTree HT,HuffmanCode HC,int cnt[],char
str[])
{
int i,s1,s2;
for(i=1;i<=2*num-1;i++)//初始化HT,2*num-1是指哈夫曼
//所有的结点数目
{
HT[i].lchild=0;HT[i].rchild=0;
HT[i].parent=0;HT[i].weight=0;
}
for(i=1;i<=num;i++) //输入num个叶结点的权值
HT[i].weight=cnt[i];
for(i=num+1;i<=2*num-1;i++)
{
select(HT,i-1,s1,s2);
HT[s1].parent=i;HT[s2].parent=i;
HT[i].lchild=s1; HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
}
//在ht[1....k]中选择parent为0且权值最小
//的两个根结点,其序号为s1和s2,i为双亲
for(i=0;i<=num;i++) //输入字符集的中字符
13
HC[i].ch=str[i]; //字符的种类
i=1;while(i<=num)
printf("字符%c次数:%d\n",HC[i].ch,cnt[i++]);
} //输出统计的情况
? 生成Huffman编码并写入文件
代码解释:根据哈夫曼树T求哈夫曼编码H。
void HuffmanEncoding(HuffmanTree T,HuffmanCode H)
{
int c,p,i; //c和p分别指示t中孩子和双亲
char cd[n]; //临时存放编码串
int start; //指示码在cd中的起始位置
cd[num]='\0'; //最后一位(第num个)放上串结束符
for(i=1;i<=num;++i)
{
start=num; //初始位置
c=i; //从叶子结点t[i]开始上溯
while((p=T[c].parent)>0) //直至上溯到t[c]是树根为止
{
cd[--start]=(T[p].lchild==c) ? '0' : '1';
c=p;
} //若t[c]是t[p]的左孩子
//则生成0;否则生成底码,
strcpy(H[i].bits,&cd[start]);
H[i].len=num-start;
}
}
代码解释:对str所代表的字符串进行编码并写入文件。将翻译的二进制码写入文本文件。
void coding(HuffmanCode HC ,char *str)
14
{
int i,j;
FILE *fp;
fp=fopen("codefile.txt","w");
while(*str)
{
for(i=1;i<=num;i++)
if(HC[i]. ch==*str){
for(j=0;j<=HC[i].len;j++)
fputc(HC[i].bits[j],fp);
break;
}
str++;
}fclose(fp);
}
? 电文译码
代码解释:代码文件codefile.txt的译码,将翻译的二进制码译成原来的字符。
char*decode(HuffmanCode HC) { FILE *fp;
char str[254]; //假设远文本文件不超过254个字符
char *p;
static char cd[n+1];
int i,j,k=0,cjs;
fp=fopen("codefile.txt","r");//一只读的方式打开文本文档
//codefile.txt
while(!feof(fp)) //feof(fp)判断文件是否真正结束,
//feof(fp)=1时文件结束 {
15
cjs=0;
for(i=0;i
#include
#include
#include
//*************************类型相关变量的定义******************************
#define n 100 //叶子结点数 #define m 2*n-1 //哈夫曼树中的结点树 typedef struct{
char ch;
char bits[9]; //存放编码位串
int len;
}CodeNode;
typedef CodeNode HuffmanCode[n+1]; typedef struct {
int weight; //权值
int lchild,rchild,parent; //左右孩子几双亲指针 }HTNode;
typedef HTNode HuffmanTree[m+1]; //0号单元不用 int num;
//**********************************建立HuffmanTree*************************
void select(HuffmanTree T,int k,int &s1,int &s2)
{ //在ht[1....k]中选择parent为0且权值最小的两个根结点的算法
//其序号为s1和s2
int i,j;int min1=101;
for(i=1;i<=k;i++)
if(T[i].weight='A'&&*p<='Z')
k=*p-64;
temp[k]++;
}
}
for(i=1,j=0;i<=26;++i)
if(temp[i]!=0 )
{
j++;
str[j]=i+64; //送对应的字母到数组中
cnt[j]=temp[i]; //存入对应字母的权值
}
return j; //j是输入字母总数 }
void ChuffmanTree(HuffmanTree HT,HuffmanCode HC,int cnt[],char str[])
{ //构造哈夫曼树HT
int i,s1,s2;
for(i=1;i<=2*num-1;i++)//初始化HT,2*num-1是指哈夫曼树所有的结点数目
{
HT[i].lchild=0;HT[i].rchild=0;
HT[i].parent=0;HT[i].weight=0;
}
for(i=1;i<=num;i++) //输入num个叶结点的权值
HT[i].weight=cnt[i];
for(i=num+1;i<=2*num-1;i++)
{ //在ht[1....k]中选择parent为0且权值最小的两个根结点
//其序号为s1和s2
//i为双亲
select(HT,i-1,s1,s2);
HT[s1].parent=i;HT[s2].parent=i;
HT[i].lchild=s1; HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
}
for(i=0;i<=num;i++) //输入字符集的中字符
HC[i].ch=str[i]; //字符的种类
i=1;while(i<=num)
printf("字符%c次数:%d\n",HC[i].ch,cnt[i++]); }
//*************************生成Huffman编码并写入文件************************
22
void HuffmanEncoding(HuffmanTree T,HuffmanCode H)
{ //根据哈夫曼树T求哈夫曼编码H
int c,p,i; //c和p分别指示t中孩子和双亲
char cd[n]; //临时存放编码串
int start; //指示码在cd中的起始位置
cd[num]='\0'; //最后一位(第num个)放上串结束符
for(i=1;i<=num;++i)
{
start=num; //初始位置
c=i; //从叶子结点t[i]开始上溯
while((p=T[c].parent)>0) //直至上溯到t[c]是树根为止
{ //若t[c]是t[p]的左孩子,则生成0;否则生成底码,
cd[--start]=(T[p].lchild==c) ? '0' : '1';
c=p;
}
strcpy(H[i].bits,&cd[start]);
H[i].len=num-start;
}
}
void coding(HuffmanCode HC ,char *str) { //对str所代表的字符串进行编码 并写入文件
int i,j;
FILE *fp;
fp=fopen("codefile.txt","w");
while(*str)
{
for(i=1;i<=num;i++)
if(HC[i]. ch==*str){
for(j=0;j<=HC[i].len;j++)
fputc(HC[i].bits[j],fp);
break;
}
str++;
}fclose(fp);
}
//*************************电文译码****************************************
char*decode(HuffmanCode HC) { //代码文件codefile.txt的译码
FILE *fp;
char str[254]; //假设远文本文件不超过254个字符
char *p;
static char cd[n+1];
int i,j,k=0,cjs;
fp=fopen("codefile.txt","r");//一只读的方式打开文本文档codefile.txt
23
while(!feof(fp))//feof(fp)判断文件是否真正结束,feof(fp)=1时文件结束
{
cjs=0;
for(i=0;i=str[i])
{
HT[i].weight=(char)'*' ;
}
}
}
//*************************打开文本****************************************
int fileopen(char string[]) {
FILE *fp;
if((fp=fopen("E:\\数据结构课程设计\\file1.txt","r"))==NULL)
{
printf("不能打开文件!\n");
exit(1);
}
while(fgets(string,100,fp)!=NULL)
printf("%s\n",string);
fclose(fp);
return 0;
}
//*************************主调函数****************************************
void main()
{
char string[100];
char *s,str[27];
int cnt[27];
HuffmanTree HT;
HuffmanCode HC;
printf("读出文本为:\n");
fileopen(string);
num=jsq(string,cnt,str); //统计字符的种类及各类字符出现的频率
DhuffmanTree(HT,cnt,str);
printf("--------------------------------------\n");
printf("HuffmanTree的初态:\n");
print1(HT);
25
ChuffmanTree(HT,HC,cnt,str); //建立哈夫曼树
HuffmanEncoding(HT,HC); //生成哈夫曼编码
coding(HC,string); //建立电文哈夫曼编码文件
printf("--------------------------------------\n");
printf("HuffmanTree的终态:\n");
print2(HT);
s=decode(HC); //读编码文件译码
printf("译码后的字符串:\n");
printf("%s\n",s); //输出译码后的字符串
printf("**********************************************************\n");
}
26