哈夫曼编码和译码的实现
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
/*哈夫曼树的应用----哈夫曼编码*/
//哈夫曼树的结点结构
typedef struct HuffmanTree{
int weight;
int parent,lchild,rchild; //编码及译码需要这三个信息
}HTNode,*HTree;
typedef char** HuffmanCode; //二级指针,存放指针
const int LeafNum=8; //叶子结点个数
void HuffmanCoding(HTree& HT,int *w,int n); //构造哈夫曼树的过程
void select(HTree HT,int t,int&s1,int&s2); //选择F中权值最小的两个结点
void HuffmanCoded(HTree& HT,HuffmanCode& HC,int n,char* p); //求解哈夫曼编码
void translate(HTree& HT,int a,int* b,int BiLen,char* p); //译码
void HuffmanCoding(HTree& HT,int *w,int n)
{
int s1,s2;
int m;
int i=0;
if(n<=1) return;
m=2*n-1; //哈夫曼树的结点个数
HT=(HTNode*)malloc(sizeof(HTNode)*(m));
HTree p=HT;
for(i=0;i<n;++i,++p,++w)
{
*(p)={*w,-1,-1,-1}; //初始化叶子结点完成
}
for(;i<m;++i,++p)
{
*(p)={-1,-1,-1,-1}; //除叶子结点外的结点初始化完成
}
cout<<"初始化后:"<<endl;
cout<<"双亲"<<'\t'<<"左孩子"<<'\t'<<"右孩子"<<'\t'<<"权值"<<endl;
for(int i=0;i<m;i++)
{
cout<<HT[i].parent<<'\t'<<HT[i].lchild<<'\t'<<HT[i].rchild<<'\t'<<HT[i].weight<<endl;
}
for(i=n;i<m;++i)
{
//在HT[1..i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2
select(HT,i,s1,s2);
HT[s1].parent=i;
HT[s2].parent=i;
HT[i].lchild=s1;
HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
}
cout<<'\n'<<"完成后:"<<endl;
cout<<"双亲"<<'\t'<<"左孩子"<<'\t'<<"右孩子"<<'\t'<<"权值"<<endl;
for(int i=0;i<m;i++)
{
cout<<HT[i].parent<<'\t'<<HT[i].lchild<<'\t'<<HT[i].rchild<<'\t'<<HT[i].weight<<endl;
}
cout<<endl;
}
void HuffmanCoded(HTree& HT,HuffmanCode& HC,int n,char* p)
{
int c,start,f;
char* cd;
HC=(HuffmanCode)malloc(sizeof(char*)*(n)); //存放字符型编码的指针
cd=(char*)malloc((n)*sizeof(char)); //存放字符型编码
cd[n-1]='\0';
for(int i=0;i<n;++i)
{
start=n-1;
for(c=i,f=HT[i].parent;f!=-1;c=f,f=HT[f].parent)
{
//从下往上找的编码逆着放,即为从上往下的顺序
if(HT[f].lchild==c) cd[--start]='0';
else cd[--start]='1';
}
HC[i]=(char*)malloc(sizeof(char)); //HC[i]即为指针
strcpy(HC[i],&cd[start]);
}
cout<<"哈夫曼编码为:"<<endl;
for(int i=0;i<8;i++)
{
cout<<p[i]<<'\t';
}
cout<<endl;
for(int i=0;i<n;i++)
{
cout<<HC[i]<<'\t';
}
cout<<endl;
}
void translate(HTree& HT,int a,int* b,int BiLen,char* p)
{
int n=2*a-2;
int i=0;
cout<<'\n'<<"传递的二进制消息为:"<<endl;
for(int i=0;i<BiLen;i++)
{
cout<<b[i];
}
cout<<'\n';
cout<<'\n'<<"对二进制编码译码后,其内容为:"<<endl;
for(;;)
{
//根据二进制编码找叶子结点
if(b[i]==0&&HT[n].lchild!=-1)
{
n=HT[n].lchild;
i++;
}
else if(b[i]==1&&HT[n].rchild!=-1)
{
n=HT[n].rchild;
i++;
}
else
{
cout<<p[n];
n=2*a-2;
if(i>BiLen-1)
{
break;
}
}
}
}
void select(HTree HT,int t,int&s1,int&s2)
{
//在HT[1...t]中选择parent不为0且权值最小的两个结点,其序号分别为s1和s2
int i,m,n;
m=n=10000;
for(i=0;i<t;i++)
{
if(HT[i].parent==-1&&(HT[i].weight<m||HT[i].weight<n))
{
if(m<n)
{
n=HT[i].weight;
s2=i;
}
else
{
m=HT[i].weight;
s1=i;
}
}
}
if(s1>s2) //s1放较小的序号
{
i=s1;
s1=s2;
s2=i;
}
}
int main()
{
int w[LeafNum]={5,29,7,8,14,23,3,11}; //叶子结点权值
char p[LeafNum]={'h','e','c','d','l','b','o','h'}; //叶子结点对应的字符
int BiMessage[]={0,1,1,0,1,0,1,1,0,1,1,0,0,1,1,1}; //传递的二进制信息
int BiLen=sizeof(BiMessage)/sizeof(int);
HTree HT;
HuffmanCode HC;
HuffmanCoding(HT,w,LeafNum);
HuffmanCoded(HT,HC,LeafNum,p);
translate(HT,LeafNum,BiMessage,BiLen,p);
return 0;
}
运行结果: