课设-哈夫曼树的实现
沈阳航空航天大学
课程设计报告
课程设计名称:数据结构课程设计
课程设计题目:哈夫曼编吗的实现
院(系):计算机学院
专业:计算机科学与技术
班级:
学号:
姓名:
指导教师:
说明:结论(优秀、良好、中等、及格、不及格)作为相关教环节考核必要依据;格式不符合要求;数据不实,不予通过。报告和电子数据必须作为实验现象重复的关键依据。
学术诚信声明
本人声明:所呈交的报告(含电子版及数据文件)是我个人在导师指导下独立进行设计工作及取得的研究结果。尽我所知,除了文中特别加以标注或致谢中所罗列的内容以外,报告中不包含其他人己经发表或撰写过的研究结果,也不包含其它教育机构使用过的材料。与我一同工作的同学对本研究所做的任何贡献均己在报告中做了明确的说明并表示了谢意。报告资料及实验数据若有不实之处,本人愿意接受本教学环节“不及格”和“重修或重做”的评分结论并承担相关一切后果。
本人签名: 日期:年月日
沈阳航空航天大学课程设计任务书
目录
学术诚信声明 (2)
课程设计任务书 (3)
1.概要设计 (5)
1.1程序所用的数据结构定义: (5)
1.2程序的主要模块结构 (5)
2.详细设计 (6)
2.1读取文本文件数据的函数: (6)
2.2筛选、记录文件数据的字符和字符出现的次数的函数 (7)
2.3创建哈夫曼树的函数: (8)
2.4从叶子到根求每个字符的哈夫曼编码的函数 (10)
2.5输出字符、字符的权重跟字符的哈夫曼编码的函数 (12)
3. 调试分析 (13)
4. 使用说明 (14)
4.1用户使用说明 (14)
4.2. 测试结果 (14)
参考文献 (17)
附录(关键部分程序清单) (18)
1.1程序所用的数据结构定义:
课设的主要数据结构为:char num[N];数组(用于读入文本文件数据),tyoedef struct English English[L];结构体数组(用于储存文本文件中字符和字符的出现次数),又运用typedef struct {int weight; int parent, lchild, echild;}HTNode,*HuffmanTree;动态分配结构体数组存储哈夫曼树,typedef char **HuffmanCode;动态分配数组存储哈夫曼树编码表。
1.2程序的主要模块结构
1读取文本文件数据的函数:
bool Readfile(int &size, char num[])
2筛选、记录文件数据的字符和字符出现的次数的函数
Sumchar(int&len,int size,int eng[],char num[],English english[]) 3创建哈夫曼树的函数
void CreatHuffmanTree(HuffmanTree &HT,int n,English english[])
4从叶子到根求每个字符的哈夫曼编码,并存储的函数
void CreatHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n)
5输出出现的字符、字符的权重跟字符的哈夫曼编码的函数
void show(HuffmanTree HT,HuffmanCode HC, int n, English english[])
图1.1 程序模块图
2.1读取文本文件数据的函数:
程序开始,运行主函数,然后进入读取文件数据的函数Readfile(int &size, char num[]);打开文件,开始输入存储文件的路径,接着利用循环由函数fread();逐个将文件数据读进数组,并计算大小size,关闭文件,读取结束,返回主函数。
图2.1 读取文件数据流程图
2.2筛选、记录文件数据的字符和字符出现的次数的函数
当文件数据读取完成后,便进入文件字符筛选的函数,进入函数,首先将记录字符的结构体数组清零,然后用循环分别将记录文件的数组num[N]里面存在的字符记录进结构体数组,并计数,在结构体数组中按照出现次数排序(即按照权重排序),输出显示文本文件中存在的字符和字符对应出现的次数。
图2.2 筛选、统计字符流程图
2.3创建哈夫曼树的函数:
程序进入创建哈夫曼树函数,先根据字符的个数,确定哈夫曼树的叶子节点,生成哈夫曼树节点类型的节点HT[i],并将节点的父亲节点,左右孩子节点的下标初始化为0;完成后,依次录入各个字符对应的字符的出现次数作为哈夫曼树的权重。初始化工作结束后,开始创建哈夫曼树:通过运用Select()函数,在HT[k](1<=k<=i-1)中选择两个其双亲域为0且权值最小的节点,并返回他们在HT中的序号s1和s2,得到新结点i,从森林中删除s1,s2,将s1和s2的双亲域由0改为i在分别将HT[s1]和HT[s2]作为双亲的左右孩子,并将他们的双亲
域赋值为i,最后将HT[s1]和HT[s2]的权值之和作为HT[i]的权值。经过n-1次的选择筛选,删除,合并最后完成创建哈夫曼树。
图2.3 创建哈夫曼树流程图
2.4从叶子到根求每个字符的哈夫曼编码的函数
哈夫曼树创建完成后,需要求哈夫曼编码。首先读入哈夫曼树,分配临时存放编码的动态数组空间,初始化编码结束符’\0’,然后逐个求字符的哈夫曼编码,start开始时指向最后,即编码结束符位置,f指向结点c的双亲结点,然后从叶子结点开始向上回溯,直到根结点,回溯一次start向前指一个位置,如果结点c 是f的左孩子,则生成代码0,结点c是f的右孩子,则生成代码1。逐个往上回溯,直到求出第i个字符的编码,每次求出一个字符便为字符的编码分配空间将其存储,直到求完整个哈夫曼树。
图2.4 求哈夫曼编码流程图
2.5输出字符、字符的权重跟字符的哈夫曼编码的函数
图2.5 输出字符权重和哈夫曼编码流程图
3. 调试分析
1.首先,程序要求从文本文件里面读取数据,在这个问题上,就遇到怎么打开文本文件和读取文本文件这样的疑问怎么来解决,(自我总结)上学期C语言学习还算可以,对于文件路径的问题,在程序运行后,需要使用者手动输入需要文件的路径,如果输入错误,提示重新启动程序,重新输入。经过几次的调试,最终完美解决这个问题。
2.因为英文文本,不仅仅包括大小写的英文字母,还有各种不同的标点符号,
刚刚开始几天,整天是想着怎么把各个标点表示并统计出来,最后,换了一个思维去想,为什么不在ASCII里面去查找英文文本里面出现的各个标点呢?,于是换了一个思维去思考,最后写出来的代码,即精炼又简单,不需要很多代码就可以把程序写完了。
3.再来就是哈夫曼树的建立了,上学期已经学习过离散数学,于是懂得了哈夫曼树构造的规则,再加上这学期学习的数据结构,对哈夫曼树又有了一个深刻的理解,加上书本的有一部分的源代码,自己又上百度去搜索资料,经过自己的多次调试,多次的测试,最后把创建哈夫曼树的程序写完了。
4.在完成哈夫曼树的构建后,在来就是编写如何去求哈夫曼编码的问题了,数据结构课本上就详细的介绍了这个算法,于是我就去仔细的阅读课本,结合自己的实际,编写出来如何去求哈夫曼树的哈夫曼编码。
5. 在其编写代码过程中遇到很多问题,如:函数之间如何传递数值,如何运用各个函数之间的递归关系,如何在各个函数之间运用分配好的动态数据~~~~等等的问题;但是我始终相信:“只要功夫深铁杵磨成针”这个道理,经过多次的单步调试和数据测试,最后还是完整的编写出来了。
4. 使用说明
4.1用户使用说明
由于是使用文件形式存储数据,在程序启动后,只需要按照你把文件所在的路径写清楚,文件路径实例: E:\\English Corpus\\01.txt 注意按照格式写清楚,即可使用本课设的程序了。
4.2. 测试结果
储存文件放在E盘根目录下,名字为data.txt。
data.txt的内容为:
程序启动后,输入文件路径:
输入路径:E:\\data.txt 回车。便输出。
参考文献
[1]严蔚敏,吴伟民.《数据结构:C语言版》北京:清华大学出版社,2007
[2]谭浩强.《C语言程设计》北京:清华大学出版社,2007
[3]王敬华,林萍,张清国《C语言程序设计教程》北京:清华大学出版社,2005
[4]左孝凌,刘永才《离散数学》上海:上海科学技术文献出版社,2014
附录(关键部分程序清单)
# include
# include
# include
# define N 2500 //定义储存字母数组的大小# define M 150
typedef struct
{
int zifu;
int cishu;
}English;
//赫夫曼树动态储存结构
typedef struct
{
int weight;
int parent, lchild, rchild;
}HTNode, *HuffmanTree;
//动态分配赫夫曼编码表
typedef char **HuffmanCode;
bool Readfile(int &size, char num[])
{
FILE *fp;
char name[50];
int i;
//打开文件读取,启动程序前,请看清楚文件路径。
printf("请输入文件路径:\n");
gets(name);
if ((fp = fopen(name, "r")) == NULL)
{
printf("路径错误、文件打开错误或文件不存在。\n请重新启动程序。\n");
exit(0);
}
for(i = 0; fread(&num[i], sizeof(char), 1, fp) != 0; i++);
//读取文件
size = i;
fclose(fp);
return 1;
}
bool Sumchar(int &len, int size, int eng[], char num[], English english[]) {
//字符的筛选和统计
int i, j, temp;
len = 0;
//-----把记录字母出现次数的数组清零-------
for(i = 33; i <= 122; i++)
{
english[i].zifu = i;
english[i].cishu = 0;
}
//-------计数字符出现的次数---------
for(i = 0; i < size ;i++)
{
for(j=33;j<=122;j++)
if(num[i] == english[j].zifu)
english[j].cishu++;
}
//-----------------起泡排序--------------------
for(i=0; i<(122-33); i++)
{
for(j=33; j<=122-i; j++)
{
if(english[j].cishu <= english[j+1].cishu)
{
temp = english[j].zifu;
english[j].zifu = english[j+1].zifu;
english[j+1].zifu = temp;
temp = english[j].cishu;
english[j].cishu = english[j+1].cishu;
english[j+1].cishu = temp;
}
}
}
//-----显示文本中含有的字符和字符的次数-----
for(i=33; i<=122; i++)
if(english[i].cishu > 0)
{
printf(" %c 出现次数: %d \n",english[i].zifu, english[i].cishu);
len++;
}
return 1;
}
//构造赫夫曼树
void CreatHuffmanTree(HuffmanTree &HT,int n,English english[])
{
//构造赫夫曼树HT