数据结构实验报告
――实验五简单哈夫曼编/译码的设计与实现
本实验的目的是通过对简单哈夫曼编/译码系统的设计与实现来熟练掌握树型结
构在实际问题中的应用。此实验可以作为综合实验,阶段性实验时可以选择其中的几个功能来设计和实现。
一、【问题描述】
利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行
译码,此实验即设计这样的一个简单编/码系统。系统应该具有如下的几个功能:
1、接收原始数据。
从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件nodedata.dat 中。
2、编码。
利用已建好的哈夫曼树(如不在内存,则从文件nodedata.dat中读入),对文件中的正
文进行编码,然后将结果存入文件code.dat中。
3、译码。利用已建好的哈夫曼树将文件code.dat中的代码进行译码,结果存入文件textfile.dat 中。
4、打印编码规则。
即字符与编码的一一对应关系。
二、【数据结构设计】
1、构造哈夫曼树时使用静态链表作为哈夫曼树的存储。
在构造哈夫曼树时,设计一个结构体数组HuffNode保存哈夫曼树中各结点的信息,根
据二叉树的性质可知,具有n个叶子结点的哈夫曼树共有2n-1个结点,所以数组HuffNode
的大小设置为2n-1,描述结点的数据类型为:
typedef struct
{
int weight;//结点权值
int pare nt;
int lchild;
int rchild;
char inf; }HNodeType;
2、求哈夫曼编码时使用一维结构数组HuffCode作为哈夫曼编码信息的存储。
求哈夫曼编码,实质上就是在已建立的哈夫曼树中,从叶子结点开始,沿结点的双亲链
域回退到根结点,没回退一步,就走过了哈夫曼树的一个分支,从而得到一位哈夫曼码值,由于一个字符的哈夫曼编码是从根结点到相应叶子结点所经过的路径上各分支所组成的0、1序列,因此先得到的分支代码为所求编码的低位码,后得到的分支代码位所求编码的高位码,所以设计如下数据类型:
#defi ne MAXBIT 10
typedef struct
int bit[MAXBIT];
int start ;
}HcodeType ;
3、文件nodedata.dat、code.dat 和textfile.dat。
三、【功能(函数)设计】
1、初始化功能模块。
此功能模块的功能为从键盘接收字符集大小n,以及n个字符和n个权值。
2、建立哈夫曼树的功能模块。
此模块功能为使用1中得到的数据按照教材中的构造哈夫曼树的算法构造哈夫曼树,即将HuffNode数组中的各个位置的各个域都添上相关的值,并将这个结构体数组存于文件hfmtree.dat 中。
3、建立哈夫曼编码的功能模块。
此模块功能为从文件nodedata.dat中读入相关的字符信息进行哈夫曼编码,然后将结
果存入code.dat中,同时将字符与0、1代码串的------ 对应关系打印到屏幕上。
4、译码的功能模块。
此模块功能为接收需要译码的0、1代码串,按照3中建立的编码规则将其翻译成字符
集中字符所组成的字符串形式,存入文件textfile.dat,同时将翻译的结果在屏幕上打印输出。
四、【编码实现】
#i nclude
#in clude
#i ncludevstri ng.h>
#i nclude
#defi ne MaxBit 10
#define Maxvalue 100〃应该大于权重之和
#defi ne Maxleaf 100
#defi ne Max node Maxleaf*2-1
typedef struct
int Ichild;
int rchild; char inf;
}HNodeType;
struct HcodeType {
int bit[MaxBit];
int start;
};
void Creat_Haffma ntree(i nt &n)
{
HNodeType *HaffNode=new HNodeType[2* n-1];
int i,j;
int m1,m2,x1,x2;
for(i=0;i<2* n-1;i++)
{
HaffNode[i].weight=0;
HaffNode[i].lchild=-1;
HaffNode[i].pare nt=-1;
HaffNode[i].rchild=-1;
HaffNode[i].i nf='0';
}
for(i=0;i< n;i++)
{
coutvv"请输入字符"< ci n>>HaffNode[i].i nf; cout?"请输入该字符的权值"< cin>> HaffNode[i].weight; } for(i=0;i< n-1;i++)〃构造哈夫曼树 { m1=m2=Maxvalue; x1=x2=0; for(j=0;j { if(HaffNode[j].pare nt==-1 &&HaffNode[j].weight { m2=m1; x2=x1; m1=H affNode[j].weight; x1=j; else { if(HaffNode[j].pare nt==-1 &&HaffNode[j].weightvm2) { m2=HaffNode[j].weight; x2=j; } } } //将找出的最小和次小合并,创造其父母结点 HaffNode[x1].pare nt=n+i; HaffNode[x2].pare nt=n+i; HaffNode[ n+i].weight=HaffNode[x1].weight+HaffNode[x2].weight; HaffNode[ n+i].lchild=x1; HaffNode[ n+i].rchild=x2; HaffNode[ n+i].i nf=NULL; } coutvv"显示存储的哈弗曼树信息:"< cout?"权值左孩子右孩子双亲"< for(i=0;i<2* n-1;i++) cout cout< cout< cout< cout< } //写入文件 fstream outfilel; outfilel.ope n("E:\\ no dedata.dat",ios::out|ios::tru nc|ios::bi nary);// 建立进行写入的文件 if(!outfile1) //没有创建成功则显示相应信息 { cout?"nodedata.dat 文件不能打开"< abort(); } for(i=0;i<2*n-1;i++) // 将内存中从HaffNode[i]地址开始的sizeof(HaffNode[i]) 的内容写入文件中 outfile1.write((char*)&HaffNode[i],sizeof(HaffNode[i])); outfile1.close ();// 关闭文件 delete []HaffNode;