树和二叉树的应用
一.实验题目:树和二叉树的应用
二.实验内容:哈夫曼编码设计
三.实验目的:掌握树和二叉树的概念及工作原理,运用其原理及概念完成上述实验题中的内容。
四、概要设计原理:
1.选择parent为-1且weight最小的两个结点。其序号分别为s1和s2
2.建立赫夫曼树叶
3.从叶子到根逆向求每个字符的赫夫曼编码
4.输出构造的树
5.输出得到的各权Huffman编码
#include<iostream>
#include<iomanip>
using namespace std;
struct HaffNode
{
int weight;
int parent;
int lchild;
int rchild;
};
struct HaffCode
{
int bit[10000]; //编码位
int start; //编码开始的位置
int weight;
char c; //编码所对应的字符
};
/*
由于n个叶子结点,要合并n-1次。每次从
还无双亲(无双亲代表还未合并过)
的叶子结点中选择权值最小的两个叶子结点进行合并,
新结点下标为这两个叶子的双亲,新结点的权值为这两个叶子权值之和,
左孩子为最小结点下标,右孩子为次小结点下标,叶子值不需要,双亲为0。
*/
void CreateHaffman(int w[],int n,HaffNode ht[])
{
//建立叶结点个数为n,权值为weight的哈夫曼树haffTree
int i,j,m1,m2,x1,x2;
//哈夫曼树haffTree初始化。n个叶结点的哈夫曼树共有2n-1个结点
for(i=0;i<2*n-1;i++)
{
if(i<n)
ht[i].weight=w[i];
else
ht[i].weight=0;
ht[i].parent=0;
ht[i].lchild=-1;
ht[i].rchild=-1;
}
//构造哈夫曼树haffTree的n-1个非叶结点
for(i=0;i<n-1;i++)
{
m1=m2=1000;
x1=x2=0;
for(j=0;j<n+i;j++)//循环找出所有权重中,最小的二个值
{
if(ht[j].weight<m1&&ht[j].parent==0)
{
m1=ht[j].weight;
x1=j;
}
else if(ht[j].weight<m2&&ht[j].parent==0)
{
m2=ht[j].weight;
x2=j;
}
}
//将找出的两棵权值最小的子树合并为一棵子树
ht[x1].parent=n+i;//新结点下标为这两个叶子的双亲,
ht[x2].parent=n+i;
ht[n+i].weight=ht[x1].weight+ht[x2].weight;//新结点的权值为这两个叶子权值之和
ht[n+i].lchild=x1;
ht[n+i].rchild=x2;
}
}
void encoded(int n,char ch[],HaffNode ht[],HaffCode hc[])
{
//由n个结点的哈夫曼树haffTree构造哈夫曼编码haffCode
HaffCode cd;
int child,parent,i,j;
//求n个叶结点的哈夫曼编码
for(i=0;i<n;i++)
{
cd.start=n-1;
cd.c=ch[i];
cd.weight=ht[i].weight;//取得编码对应权值的字符
child=i;
parent=ht[child].parent;//由叶结点向上直到根结点
while(parent!=0)
{
if(ht[parent].lchild==child)
cd.bit[cd.start]=0;//左孩子结点编码0
else
cd.bit[cd.start]=1;//右孩子结点编码1
cd.start--;
child=parent;
parent=ht[child].parent;
}
//保存叶结点的编码和不等长编码的起始位
for(j=cd.start+1;j<n;j++)//重新修改编码,从根节点开始计数
hc[i].bit[j]=cd.bit[j];
hc[i].start=cd.start;
hc[i].weight=cd.weight;//保存编码对应的权值
hc[i].c=cd.c;
cout<<"字符"<<cd.c<<"的权值为:"<<hc[i].weight<<" code=";
for(j=hc[i].start+1;j<n;j++)
cout<<hc[i].bit[j];
cout<<endl;
}
}
void transcode(int n,HaffNode ht[],HaffCode hc[])
{
int a=2*n-2;
char b;
cout<<"请输入一串二进制编码(0,1以外的数结束)"<<endl;
cin>>b;
while((b=='0')||(b=='1'))
{
if(b=='0')
a=ht[a].lchild;
else
a=ht[a].rchild;
if(ht[a].lchild==-1)
{
cout<<hc[a].c;
a=2*n-2;
}
cin>>b;
}
}
int main()
{
int w[1000];//权值数组
char ch[1000];//代码数组
int n,a;
cout<<"共有叶子数:"<<endl;
cin>>n;
cout<<"依次输入每个叶子的权值:"<<endl;
for(a=0;a<n;a++)
cin>>w[a];
cout<<"依次输入每个叶子所代表代码:"<<endl;
for(a=0;a<n;a++)
cin>>ch[a];
HaffNode* ht=new HaffNode[2*n-1];//树结点数组
HaffCode* hc=new HaffCode[n];//编码数组
CreateHaffman(w,n,ht);
encoded(n,ch,ht,hc);
transcode(n,ht,hc);
return 0;
}