数据结构课程设计哈夫曼编译器
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
中南大学
数据结构课程设计报告
题目哈夫曼编译器
学生
指导教师
学院信息科学与工程学院
专业班级计科1302
目录
实验要求 (3)
问题描述 (3)
问题解决方法 (3)
程序模块功能及流程图 (4)
调试与测试 (8)
测试结果 (9)
心得体会 (11)
源代码 (12)
一.实验要求
(1)从键盘读入字符集大小n , 以及n个字符和权值,建立哈夫曼树。
(2)利用已建好的哈夫曼树对文件正文进行编码,将结果存入相关文件中。
(3)利用已建好的哈夫曼树将编码文件中的代码进行译码,结果存入文件中。
(4)输出代码文件,以紧凑格式显示。
二.问题描述
利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码。对于双向传输信息的信道,每端都需要一个完整的编译码系统。为这样的信息收发站编写哈夫曼编译系统。
哈夫曼树又称最优二叉树,构造的规则即给定n个权值不同的叶子节点,构造一棵二叉树,使二叉树的带权路径长度达到最小。具体做法即要使权值较大的结点离根节点较近,权值较小的结点离根节点较远。
三.问题解决方法
建立哈夫曼树时要进行多次选择,每次选择出权值最小和次小的两个节点,将两结点权值相加,作为新生成父节点的权值。并分别将其作为左、右孩子。再将父节点加入需选择的结点序列中,继续选择,直到将所有节点都选完为止,构成一颗哈夫曼树。每种字符对应一个节点,将每种字符的出现次数作为对应节点权值。
在编码过程中,较科学的方法是统计文章中每种字符出现的频率,并以其作为对应节点的权值,使出现频率较高的节点离根结点较近,从而使出现频率越高的字符所得的编码位数越少,这样做得到的编码结果是最简练的,也更有利于译码。
编码需从叶节点向上回溯,若叶节点为其父结点的左孩子,则编码为0,若为右孩子,则编码为1。然后将父节点作为下一轮循环的子节点,继续重复上述步骤,直至到达根节点为止,即得到初始叶节点对应的编码。
译码是编码的逆过程,所以译码只需读入编码位串,从根结点开始,若读到0,则走向左孩子,读到1,则走向右孩子。并将对应的子节点作为下一轮循环
的叶节点,重复上述步骤,直至到达最终叶节点,该叶节点即为编码对应的节点。四.程序模块功能及流程图
1.主要程序模块及功能
(1)建立哈夫曼树
数据结构:
tree[]为定义在Huffmantree类上的数组对象。
n为节点个数,即字符种类数。
m为建好的哈夫曼树的总节点数,在哈夫曼树中,m=2*n-1。
Smal、small2分别存放每轮循环中权值最小和次小的节点的权值。
p1,p2分别记住每次合并时权值最小和次小的两个根结点的下标。
对应代码段:
for(i=0;i t ree[i]=new Huffmantree(); } float small1,small2; //建立哈夫曼树 for(i=0;i tree[i].parent=0; tree[i].lchild=-1; tree[i].rchild=-1; tree[i].weight=0; } for(i=0;i 叶节点对应一种字符 { tree[i].ch=ch[i]; tree[i].weight=arr[i]; } for(i=n;i { p1=0;p2=0; small1=10000;small2=100; for(j=0;j if(tree[j].parent==0) if(tree[j].weight { small2=small1; small1= tree[j].weight; p2=p1; p1=j; } else if(tree[j].weight { small2=tree[j].weight; p2=j; } tree[p1].parent=i; //建立子节点与父节点间的对应关系,并将父节点 权值赋为两子节点权值之和tree[p2].parent=i; tree[i].lchild=p1; tree[i].rchild=p2; tree[i].weight=tree[p1].weight+tree[p2].weight; } (2)编码模块 数据结构: Code[]为定义在codetype类上的数组对象。 c为缓冲变量,其值为当前节点的下标值。 p为父节点的下标值。 Start为每个字符编码位串中第一个字符的起始位置。 对应代码段: int c,p; //编码部分,c为当前节点编号,p为其父节点编号Code=new Codetype[n]; for(i=0;i C ode[i]=new Codetype(); C ode[i].bits=new Character[n]; } for(i=0;i { Code[i].start=n; //start为编码位串的起始位置 Code[i].ch=tree[i].ch; c=i; p=tree[i].parent; while(p!=0) { Code[i].start--;