哈夫曼树&&哈夫曼编码
1、源代码(详解见注释)
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct {
int weight;
int parent,lchild,rchild;
}HTNode,*HuffmanTree; //动态分配数组存储赫夫曼树
typedef char* HCNode;
typedef HCNode* HuffmanCode; //动态分配数组存储哈夫曼编码表
void Select(HuffmanTree HT,int m,int *s1,int *s2){ //在HT【1,m】中选择parent为0且weight最小的两个结点,其序号分别为s1,s2
int i,min1=2000,min2=2000,a=0,b=0;
for(i=1;i<=m;i++){
if(HT[i].parent==0&&(HT[i].weight<min1||HT[i].weight<min2)){
if(HT[i].weight<min1){
min1=HT[i].weight;
a=i;
}else{
min2=HT[i].weight;
b=i;
}
}
}
*s1=a;*s2=b;
}
//w存放n个字符的权值,构造赫夫曼树HT
void HuffmanCoding(HuffmanTree *HT,int *w,int n){
if(n<=1) return;
int m=2*n-1; //n个字符(叶子节点)需要2n-1个节点
*HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); //0号单元未用
HuffmanTree p;
int i,s1,s2;
for(i=1; i<=m; i++) //初始化结点[1...2*n+1],存储叶子结点及双亲结点
{
if(i<=n)
(*HT)[i].weight = w[i-1]; //[1...n],叶子结点
else
(*HT)[i].weight = 0; //[n+1...2*n+1],双亲结点
(*HT)[i].parent = 0;
(*HT)[i].lchild = 0;
(*HT)[i].rchild = 0;
}
for(i=n+1;i<=m;i++){
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;
}
}
//从叶子到根逆向求每个字符的赫夫曼编码
void HuffmanCodingFinding(HuffmanTree HT,HuffmanCode *HC,int n){
*HC=(HuffmanCode)malloc((n+1)*sizeof(char*)); //相当于二维数组,分配n个字符编码的头指针向量,0号单元不用
char *cd;
int start;
cd=(char*)malloc(n*sizeof(char)); //分配求编码的工作空间(暂时存放),每个编码最多有n-1个字符组成
cd[n-1]='\0'; //结束标志
for(int i=1; i<=n; i++) //逐次求每个叶子结点的哈夫曼编码
{
start = n - 1; //赋值起点
for(int 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]); //从start开始复制
}
free(cd);
}
//测试函数
int main()
{
int w[8]={5,29,7,8,14,23,3,11};
HuffmanTree HT;
HuffmanCode HC;
HuffmanCoding(&HT,w,8);
HuffmanCodingFinding(HT,&HC,8);
for(int i=1;i<=8;i++)
printf("%s\n",HC[i]);
}
2、结果