哈夫曼编码的基本步骤:
(1)把概率最小的两个符号组成一个新的节点
(2)重复步骤,直到概率和为1
(3)总根节点开始到相应于每个符号的“树叶”,概率大的标“1”,概率小的标“0”
(4)从根节点开始,对符号进行编码
1、定义结构体
typedef struct
{
float weight;
int parent,lchild,rchild;
}HTNode;
typedef struct
{
char data;
float weight;
char code[N];
}HTNode;
2、mian函数,调用Huffman函数进行编码,并计算编码的平均长度
void main()
{
int i,n;
float l;
HTNode ht[M+1];
HTCode hc[N+1];
Init(hc,&n);
HuffmanCoding(ht,hc,n);
for( i=1;i<=n;i++)
printf("\n %c的编码结果是:%s",hc[i].data,hc[i].code);
//计算平均码长
l=0;
for( i=1;i<=n;i++)
{
l+=strlen(hc[i].code)*hc[i].weight;
}
printf("\n 哈夫曼编码的平均码长是:%f\n",l);
getchar();等待用户按任意键返回,阻止运行黑框闪退问题
for(i=1;i<=n;i++)
printf("\n %c的编码结果是:%s",hc[i].data,hc[i].code);
l=0;
for(i=1;i<=n;i++)
l+=strlen(hc[i].code)*hc[i].weight;
printf("\n 赫夫曼编码的平均码长是: %f\n",l);
}
3、创建Init,用于初始化待编码项的名称和权值
void Init(HTCode hc[],int*n)
{
int i;
printf("\n 请输入要编码的总项数n=");
scanf("%d",&(*n));
fflush(stdin);
printf("\n 输入%d项带编码数的信息\n",*n);
for(i=1;i<=*n;i++){
printf("\n第%d的名称是:",i);
scanf("%c",&(hc[i].data));
fflush(stdin);
}
printf("\n 注意:各项带编码数的权重之和应该为1 \n",*n);
for(i=1;i<=*n;i++){
printf("\n第%d的权重是:",i);
scanf("%f",&(hc[i].weight));
}
}
4、创建HuffmanCoding函数,其主要的功能是:先构造二叉树,然后再根据构造的二叉树,进行哈夫曼编码
void HuffmanCoding(HTNode ht[],HTCode hc[],int n)
{
char cd[N];
int i,m,c,f,s1,s2,start;
m=2*n-1;
for(i=1;i<=m;i++){
if(i<=n)
ht[i].weight=hc[i].weight;
else
ht[i].weight=0.0;
ht[i].parent=ht[i].lchild=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;
}
for(i=1;i<=m;i++){
printf("\n 第%d个节点的权重是:%f",i,ht[i].weight);
printf("\n 第%d个节点的左子节点是:%d",i,ht[i].lchild);
printf("\n 第%d个节点的右子节点是:%d",i,ht[i].rchild);
printf("\n 第%d个节点的父节点是:%d",i,ht[i].parent);
}
for(i=0;i<N;i++){
cd[i]=' ';
}
cd[n-1]='\0';
for(i=1;i<=n;i++){
start=n-1;
for(c=i,f=ht[i].parent;f;c=f,f=ht[f].parent)
{
if(ht[f].lchild==c)
cd[--start]='0';
else
cd[--start]='1';
}
strcpy(hc[i].code,&cd[start]);
}
}
5、创建Select函数,用于在剩余二叉树根节点和新产生的根节点中选出权值最小的两项
void Select(HTNode ht[],int k,int *s1,int *s2)
{
int i;
for(i=1;i<=k;k++){
if(ht[i].parent==0)
{
*s1=i;
break;
}
}
for(i=1;i<=k;i++)
{
//if(ht[i].parent==0&&ht[i].weight<ht[*s1].weight && fabs(ht[i].weight-ht[*s1].weight)>1e-6)
if(ht[i].parent==0&&ht[i].weight<ht[*s1].weight&&fabs(ht[i].weight-ht[*s1].weight)>1e-6)
*s1=i;
}
for(i=1;i<=k;i++)
{
if(ht[i].parent==0&&i!=*s1)
{
*s2=i;
break;
}
}
for(i=1;i<=k;i++)
{
//if(ht[i].parent==0&&i!=*s1&&ht[i].weight<ht[*s2].weight && fabs(ht[i].weight-ht[*s2].weight)>1e-6)
if(ht[i].parent==0&&i!=*s1&&ht[i].weight<ht[*s2].weight&&fabs(ht[i].weight-ht[*s2].weight)>1e-6)
*s2=i;
}
printf("\n 这是 *s1:%d\n",*s1);
printf("\n 这是 *s2:%d\n",*s2);
}