哈夫曼树及其哈夫曼编码
输入5种字符以及他们的权值:a:10, b:5, c:20, d:8,e:15
第一步:构建哈夫曼树
第二步:为哈夫曼树的每一条边编码(左0右1),图中没有标
代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 5 //带权值的叶子节点数
#define M 2*N-1 //n个叶子节点构造的哈夫曼树有2n-1个结点
#define MAX 10000
typedef char TElemType;
typedef struct{
unsigned int weight; //权值只能是正数
unsigned int parent,lchild,rchild;
}HTNode;
typedef HTNode HuffmanTree[M+1]; //动态分配数组存储哈夫曼树,0号单元不适用
typedef char *HuffmanCode[N+1]; //动态分配数组存储哈夫曼编码
//在HT[1...k]里选择parent为0的且权值最小的2结点,其序号分别为s1,s2,
void Select(HuffmanTree HT,int k,int &s1,int &s2){
unsigned int tmp = MAX ,temp = 0;
for(int i=1;i<=k;i++){
if(!HT[i].parent ){ //双亲为0
//找出最小值
if(tmp>HT[i].weight ){
tmp = HT[i].weight ; //tmp最后为最小的weight
temp = i;
}
}
}
s1 = temp;
tmp = MAX;
temp = 0;
for(int i = 1;i<=k;i++){
if((!HT[i].parent )&& i!=s1){
//找出第二个小值
if(tmp > HT[i].weight ){
tmp = HT[i].weight ;
temp = i;
}
}
}
s2 = temp;
}
void CreateHuffmanCoding (HuffmanTree &HT,HuffmanCode &HC,int *w,int n){
//存放n个字符的权值(均>0),构造哈夫曼树HT,并求出n个字符的哈夫曼树HC
int i;
if(n<=0) //空树
return ;
//对树赋初值
for(i = 1;i<=n;i++){ //将哈夫曼表的双亲,左右子树置0
HT[i].weight = w[i];
HT[i].lchild = 0;
HT[i].parent = 0;
HT[i].rchild = 0;
}
for(i = n+1;i<=M;i++){
HT[i].weight = 0;
HT[i].lchild = 0;
HT[i].parent = 0;
HT[i].rchild = 0;
}
//创建哈夫曼树
for(i=n+1;i<=M;i++){
int 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 ; //值i的权值
}
//为每个字符求解哈夫曼编码,从叶子到根逆向求解每个字符的哈夫曼编码
char *ch = (char *)malloc (n*sizeof (char));
ch[n-1]='\0'; //编码结束符
int start ,c,f;
for(int i = 1;i<=N;i++){ //逐个字符求哈夫曼编码
start = N-1; //编码结束的位置
for(c=i,f=HT[i].parent ;f!=0;c=f,f=HT[f].parent ){ //从叶子到根 的逆向求编码
if(HT[f].lchild == c){
ch[--start] = '0';
}else{
ch[--start] = '1';
}
}
//每次ch的后N-start个位置有编码存在
HC[i]= (char *)malloc((N-start)*sizeof (char));
//将ch的后N-start个元素赋值给H[i] 指向的字符串
strcpy (HC[i],&ch[start]);
}
}
//打印哈夫曼树
void prinfHuffmanTree(HuffmanTree HT,char ch[]){
printf("data\tweight\tparent\tlchild\trchild\n");
for(int i = 1;i<=M;i++){
if(i>N){
printf(" -\t%d\t%d\t%d\t%d\n",HT [i].weight ,HT[i].parent ,HT[i].lchild ,HT[i].rchild );
}else{
printf(" %c\t%d\t%d\t%d\t%d\n",ch[i], HT [i].weight ,HT[i].parent ,HT[i].lchild ,HT[i].rchild );
}
}
}
//输出哈夫曼编码
void printHuffmanCoding(HuffmanCode HC,char ch[]){
for(int i = 1; i<=N;i++){
printf("%c:%s\n", ch[i],HC[i]);
}
printf("\n");
}
int main(){
HuffmanTree HT;
HuffmanCode HC;
TElemType ch[N+1];
int w[N+1];
printf("\n********哈夫曼树及哈夫曼编码的存储表示:*********\n");
printf("请输入%d 个字符以及字符对应的权值:\n",N);
for(int i = 1;i<=N;i++){
scanf("%c%d",&ch[i],&w[i]);
getchar(); //去掉换行符
}
CreateHuffmanCoding (HT,HC,w,N); //创建哈夫曼树
printf("\n********哈夫曼树如下:*********\n");
prinfHuffmanTree(HT,ch);
printf("\n********哈夫曼编码:*********\n");
printHuffmanCoding(HC,ch);
return 0;
}
运行截图: