一、 实验目的
通过对简单哈夫曼编译码系统的设计与实现来熟练掌握树型结构在实际问题中的应用。
二、 实验问题描述
利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端勇冠一个编码系统对待数据预先编码,在接收端将传来的数据进行译码,此实验即设计一个简单编码系统。
三、实验步骤
1、实验问题分析
此实验要实现这样几个功能:1.接收原始数据2.编码3.译码4.打印编码规则5.打印哈夫曼树。所以在编写程序前应先解决两个问题:1.构造哈夫曼树时使用静态链表作为哈夫曼树的存储。描述结点的数据类型为:
typedef struct{
int weight;
char letter;
int parent;//双亲结点下标
int left;
int right;}HuffNode;
2.求哈夫曼编码使用一维结构数组HuffCode作为哈夫曼编码信息的存储。求哈夫曼编码实质上就是在已建立的哈 夫曼树中,从叶子结点开始,沿结点的双亲链域回退到根结点,每加退一步,就走过了哈 夫曼树的一个会支,从而得到一位哈夫曼码值,由于一温和派字符的哈夫曼编码是从根结点到相应叶子结点所经过的路径上各分支所组成的0、1序列,从而得到的分支代码为所求编码的低位码,后得到的分支代码为所求编码的高位码,数据类型为:
typedef struct{//结点的哈夫曼编码类型
int bit[MaxBit];//存放编码数组
int start;//编码起始下标
int weight;//字符的权值
}Code;
2、功能函数设计
1、建立哈夫曼树的功能模块:void MakeHufm(HuffNode HuffN[],int n)。此程序构造哈夫曼树,在此过程中哈夫曼树HuffN初始化、输入第字母和权值。并将构造后的哈夫曼树存入“hfmtree.dat”。
2.建立哈夫曼编码的功能模块:void HuffCode(int n)。此模块对已建立的哈夫曼树进行哈夫曼编码,然后将结果存入huffCode.dat中,同时将字符与0、1代码串的一一对应关系打印到屏幕上。
四、实验结果(程序)及分析
1、实验主要模块
建立哈夫曼树的功能模块:
void MakeHufm(HuffNode HuffN[],int n){
int i,j,x1,x2,m1,m2;
//HuffNode *HuffN[];
//-------哈夫曼树HuffN初始化-----------------//
for(i=0;i<2*n-1;i++){
HuffN[i].letter='0';
HuffN[i].weight=0;
HuffN[i].parent=-1;
HuffN[i].left=-1;
HuffN[i].right=-1;}
for(i=0;i<n;i++){
cout<<"请输入第"<<i+1<<"个字母和权值";
cin>>HuffN[i].letter;cin>>HuffN[i].weight;}
//-----------构造哈夫曼树HuffN的N-1个非叶结点-------//
for(i=0;i<n-1;i++){
m1=m2=MaxV;
x1=x2=0;
for(j=0;j<n+i;j++){
if(HuffN[j].parent==-1&&HuffN[j].weight<m1){
m2=m1;
x2=x1;
m1=HuffN[j].weight;
x1=j;
}
else if(HuffN[j].parent==-1&&HuffN[j].weight<m2){
m2=HuffN[j].weight;
x2=j;} }
//将找出的两棵权值最小的子树合并为一棵子树
HuffN[x1].parent=n+i;
HuffN[x2].parent=n+i;
HuffN[n+i].weight=HuffN[x1].weight+HuffN[x2].weight;
HuffN[n+i].left=x1;
HuffN[n+i].right=x2; }
ofstream outfile;
outfile.open("HuffN.dat",ios::out|ios::trunc);
if(!outfile){cout<<"文件打开失败"<<endl;}
outfile<<"letter"t"<<"weight"t"<<"left"t"<<"right"t"<<"parent"t"<<""n";
for(i=0;i<n;i++)
{outfile<<HuffN[i].letter<<""t"<<HuffN[i].weight<<""t"<<HuffN[i].left<<""t"<<HuffN[i].right<<""t"<<HuffN[i].parent<<""n";
}outfile.close(); }
建立哈夫曼编码的功能模块void HuffCode(int n){
Code code[Maxleaf];Code cd;
HuffNode HuffN[MaxN];
int child,parent;int i;int j;
//求N个结点的哈夫曼编码
MakeHufm(HuffN,n);
for(i=0;i<n;i++){
cd.start=n-1;//不等长的编码最后一位为N-1
child=i;
parent=HuffN[child].parent;
while(parent!=-1)
{
if(HuffN[parent].left==child)
cd.bit[cd.start]=0;
else
cd.bit[cd.start]=1;
cd.start--;
child=parent;
parent=HuffN[child].parent;
}
for(j=cd.start+1;j<n;j++)
code[i].bit[j]=cd.bit[j];
code[i].start=cd.start;
}ofstream outfile;outfile.open("huffCode.dat");//保存程序编码后的字母和编码
if(!outfile){cout<<"文件打开失败"<<endl;}
outfile<<"bit"t"<<"start"t"<<"weight"t"<<""n";
for(i=0;i<n;i++){cout<<HuffN[i].letter<<"--";
for(j=code[i].start+1;j<n;j++){
outfile<<code[i].bit[j]<<""t"<<code[i].start<<""t"<<code[i].weight<<endl;
cout<<code[i].bit[j];} //格式化输出编码
cout<<endl;}
outfile.close();
}
2、测试数据
请输入要创建的叶子结点个数N:
6
请输入第1个字母和权值a 5
请输入第2个字母和权值b 3
请输入第3个字母和权值k 8
请输入第4个字母和权值s 0
请输入第5个字母和权值w 1
请输入第6个字母和权值p 3
a--10
b--1111
k--0
s--11100
w--11101
p--110
3、调试过程中出现的问题以及解决策略。
一开始我把此程序写成了一个哈夫曼类,由于类掌握的不太熟练所以只好中途放弃。当按照书上的编写过程编程后出现了参数传递的问题:构造的哈夫曼树如何传送给void HuffCode(int n),并按照自己的意途进行编码。把构造哈夫曼树的函数放在void HuffCode(int n)中直接进行调用后解决了此问题。类型的匹配,函数参数的传递。通过对程序的逐步调试,更深刻地了解了程序的执行,对树这一结构有了深一步的认识。
对文件的使用:要使程序按照一定的格式进行输出,使输出的内容具有较强的可读性,要在输出时打印制表符。通过对文件操作的使用,使对文件的操作更灵活。但发现在C++中仍有许多类的知识要学习,在树的程序编写上还需要进一步地巩固。要学会分析问题和解决问题,以及读别人的程序要懂得原理。
在调试的过程中,还出现了指针的使用错误。通过对指针的修改,从而对数据结构定义的数据类型有了更进一步的了解。通过程序的编写,发现了自己在知识上的许多不足。
浙公网安备 33010602011771号