首先给出Huffman树的定义:假设有n个权值{w1,w2...wn},试构造一棵有n个叶子结点的二叉树,每个叶子结点带权为wi,则其中带权路径长度最小的二叉树称作最优二叉树或Huffman树。 下面的求解过程一顺序结构存储Huffman树,具体代码如下:
//----Huffman树和Huffman编码的存储表示
typedef struct HTNode{
unsigned int weight;
unsigned int parent,lchild,rchild;
void InitHTNode(unsigned int w,unsigned int p,unsigned int l,int r){
weight=w; parent=p; lchild=l; rchild=r;
}
}HTNode,*HuffmanTree; //动态分配数组存储Huffman树
typedef char **HuffmanCode;//动态分配数组存储Huffman编码表
//在HT[1...n] 中选择parent为0且weight最小的两个结点,其序号分别是s1,s2
void Select(HuffmanTree HT,int n,int &s1,int &s2){
//先找最小 s1表示
for(int i=1;i<=n;++i){
if(HT[i].parent==0){
s1=i;
break;
}
}
for(int i=2;i<=n;++i){
if(HT[i].parent==0){
if(HT[s1].weight>HT[i].weight) s1=i;
}
}
for(int i=1;i<=n;++i){
if(HT[i].parent==0&&i!=s1){
s2=i;
break;
}
}
for(int i=2;i<=n;++i){
if(HT[i].parent==0&&i!=s1){
if(HT[s2].weight>HT[i].weight) s2=i;
}
}
}
//求Huffman编码
void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n){
//w存放n个字符的权值(均大于0),构造Huffman树HT,并求出n个字符的Huffman编码
if(n<=1) return;
int m=2*n-1; //有n个叶子结点的二叉树共有2*-1个结点
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
HTNode* p=NULL;
int i=0,s1=0,s2=0;
for(p=HT+1,i=1;i<=n;++i,++p,++w)
p->InitHTNode(*w,0,0,0); //初始化n个叶子结点
for(;i<=m;++i,++p)
p->InitHTNode(0,0,0,0); //初始化非叶子结点
for(i=n+1;i<=m;++i){ //建立Huffman树
//在HT[1...i-1] 中选择parent为0且weight最小的两个结点,其序号分别是s1,s2
Select(HT,i-1,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;
}
//----从叶子到根逆向求每个字符的Huffman编码---
HC=(HuffmanCode)malloc((n+1)*sizeof(char*)); //分配n个字符编码的头指针向量
char * cd=NULL;
cd=(char*)malloc(n*sizeof(char)); //分配求编码的工作空间
cd[n-1]='\0'; //编码结束符
int start=0,f=0;
unsigned int c=0;
for(i=1;i<=n;++i){ //逐个字符求Huffman编码
start=n-1; //编码结束符位置
for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent){
if(HT[f].lchild==c) cd[--start]='0';
else
cd[--start]='1';
}
HC[i]=(char*)malloc((n-start)*sizeof(char));
strcpy(HC[i],&cd[start]); //从cd复制编码串到HC
}
free(cd);
}
void PrintHuffmanCode(char * c){
while(*c!=0){
cout<<*c;
++c;
}
c=NULL;
}
int main()
{
HuffmanTree HT;
HuffmanCode HC;
int w[7]={3,7,4,6,1,5,2};
int n=7;
HuffmanCoding(HT,HC,w,n);
for(int i=1;i<=n;++i){
cout<<i<<":";
PrintHuffmanCode(HC[i]);
cout<<endl;
}
cout<<endl<<endl;
for(int i=1;i<=13;++i){
cout<<i<<" weight:"<<HT[i].weight<<" parent: "<<HT[i].parent<<" lchild: "<<HT[i].lchild<<" rchild: "<<HT[i].rchild<<endl;
}
cout << "Hello world!" << endl;
return 0;
}
运行结果:
一开始写Select(HuffmanTree HT,int n,int &s1,int &s2)函数时候 s1,s2的初始化错误,一定要保证s1,s2对应结点的parent为0。