哈夫曼编码也称前缀编码,它是根据每个字符出现的频率而进行编码的,要求任一字符的编码都不是其它任意字符编码的前缀且字符编码的总长度为最短。它主要应用于通信及数据的传送以及对信息的压缩处理等方面。哈夫曼编码的基础是依据字符出现的频率值而构造一棵哈夫曼树,从而实现最短的编码表示最常用的数据块或出现频率最高的数据。
某个信息所含的五种字符的出现次数分别为:
a - 16,b - 7,c - 6,d - 6,e - 5. 现要求对这五种字符进行哈夫曼编码。
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#define MAX 100
//哈夫曼树结点结构体
typedef struct{
int weigth;
int parent;
int rchild;
int lchild;
}HTNode,*HuffmanTree;
//需要编码的字符串数组
static char N[MAX];
//定义哈夫曼编码数组(char型二级指针(指向指针的指针))
typedef char **HuffmanCode;
//最小与次小的结点
typedef struct{
int s1;
int s2;
}MinCode;
//函数声明
MinCode Select(HuffmanTree HT,int n);
//哈夫曼树,哈夫曼编码,权值数组,叶子结点数量
HuffmanCode HuffmanCoding(HuffmanTree HT,HuffmanCode HC,int *w,int n){
int i,s1=0,s2=0;
//哈夫曼树
HuffmanTree p;
//暂存哈夫曼编码数组
char *cd;
int f,c,start,m;
//最小与次小节点
MinCode min;
//m为总结点数
m=2*n-1;
//动态创建哈夫曼树
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
//HT前n个为叶子节点,后面n-1个为非叶子节点
//初始化n个叶子节点
for(p=HT,i=0;i<=n;i++,p++,w++){
p->weigth=*w;
p->parent=0;
p->rchild=0;
p->lchild=0;
}
//初始化从后面数n-1个非叶子节点
for(;i<=m;i++,p++){
p->weigth=0;
p->parent=0;
p->lchild=0;
p->rchild=0;
}
//创建哈夫曼树
for(i=n+1;i<=m;i++){
//寻找最小与次小
min=Select(HT,i-1);
s1=min.s1;
s2=min.s2;
//合并树
HT[s1].parent=i;
HT[s2].parent=i;
HT[i].lchild=s1;
HT[i].rchild=s2;
HT[i].weigth=HT[s1].weigth+HT[s2].weigth;//合并权值
}
//输出创建的树
printf("哈夫曼树列表:\n");
printf("序号\t权值\t父节点\t左孩子\t右孩子\n");
for(i=1;i<=m;i++)
printf("%d\t%d\t%d\t%d\t%d\n",i,HT[i].weigth,HT[i].parent,HT[i].lchild,HT[i].rchild);
//动态创建哈夫曼编码
HC=(HuffmanCode)malloc((n+1)*sizeof(char *));
//动态创建暂存哈夫曼编码数组
cd=(char *)malloc(n*sizeof(char *));
//最后一位赋值为结束符
cd[n-1]='\0';
for(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)
cd[--start]='0';
else
cd[--start]='1';
}
//对第i个字符分配空间
HC[i]=(char *)malloc((n-start)*sizeof(char *));
//将cd暂存的复制到HC
strcpy(HC[i],&cd[start]);
}
free(cd);
return HC;
}
//选出最小与次小的函数
MinCode Select(HuffmanTree HT,int n){
int min,secmin;
int i,s1,s2;
MinCode code;
s1=1;
s2=1;
min=0x3f3f3f3f;
for(i=1;i<=n;i++){
if(HT[i].weigth<min && HT[i].parent==0){
min=HT[i].weigth;
s1=i;
}
}
secmin=0x3f3f3f3f;
for(i=1;i<=n;i++){
if((HT[i].weigth<secmin) && (i!=s1) && HT[i].parent==0){
secmin=HT[i].weigth;
s2=i;
}
}
code.s1=s1;
code.s2=s2;
return code;
}
int main(){
HuffmanTree HT=NULL;
HuffmanCode HC=NULL;
int *w=NULL;
int i,n;
printf("请输入要编码的字符串:");
gets(N);
n=strlen(N);
w=(int *)malloc((n+1)*sizeof(int *));
w[0]=0;
printf("依次输入权值:\n");
for(i=1;i<=n;i++){
printf("w[%d]=",i);
scanf("%d",&w[i]);
}
HC=HuffmanCoding(HT,HC,w,n);
printf("哈夫曼编码:\n");
printf("字符\t权值\t编码\n");
for(i=1;i<=n;i++)
printf("%c\t%d\t%s\n",N[i-1],w[i],HC[i]);
printf("哈夫曼编码:\n");
for(i=1;i<=n;i++)
printf("%s\t",HC[i]);
printf("\n");
return 0;
}