定义的结构体
typedef struct node
{
char elem;
float weight;
int loc;
int lch,rch,parent;
}Node;
计算字符串中的权重
- 没什么技巧,直接计算
int CalculateWeight(char a[],char b[],float weight[])
{
int i=0,j;
int len1=0,len2=0;
while(a[i]!='\0')//计算输入字符的个数
{
i++;
}
len1=i;//记录输入字符的个数
i=0;
while(a[i]!='\0')//计算输入数据的权重
{
for(j=0;j<len2;j++)//判断已记录数据是否有该数据
{
if(a[i]==b[j])
{
i++;
weight[j]++;
break;
}
}
if(j==len2)//已记录数据不存在该字符则新增该字符
{
b[len2]=a[i];
weight[len2]++;
len2++;
i++;
}
}
for(i=0;i<len2;i++)
{
weight[i]=weight[i]/len1;//计算所占百分比
}
return len2;//返回不重复的字符数
}
构造Huffman树
- 由于叶结点的数目n是已经知道的,故我可以知道所要构建的二叉树的结点一共为2n-1个,故可以申请数量为2n-1的动态数组,其中每个数组中的元素为一个Node。
- 之后将数组初始化,并且将二叉树的叶结点赋值到新开的数组T[ ]中。
- 之后根据寻找无父母的结点中的最小权重点和次小权重点进行合并成一个新的结点,将新的结点依次存储在T[ ]数组中,即构建出了一棵权重最小的二叉树。
为Huffman树赋值编码
- 申明一个二维数组codenum[ ] [ ] 数组用于存储编码,初始化该数组。
- 申请一个队列,长度为Huffman树的结点数,辅助计算编码
- 设根结点的编码为空,其中,向左子树走一步则编码为0,向右子树走一步则编码为1(在编码的计算中,运用到了BFS遍历。
void Codenum(Node T[],int l)
{
char codenum[MAX][MAX];//用于存储前缀编码
int top=0,tail=0;
int len=0,len1=0,len2=0;
Node *a;
Node temp;
memset(codenum,0,sizeof(codenum));
len=2*l-1;
a=(Node*)malloc(len*sizeof(int));//用于充当队列
a[tail].lch=T[len-1].lch;//队首赋初值
a[tail].rch=T[len-1].rch;
tail++;//队尾+1
while(top!=tail)
{
if(len==1)
{
temp.lch=a[top].lch;
temp.rch=a[top].rch;
temp.loc=len-1;
codenum[len-1][0]='0';
top++;
}
else
{
temp.lch=a[top].lch;
temp.rch=a[top].rch;
temp.loc=a[top].loc;
top++;//出队操作
if(temp.lch!=-1)//查看是否有左子树
{
a[tail].lch=T[temp.lch].lch;
a[tail].rch=T[temp.lch].rch;
a[tail].loc=temp.lch;
tail++;
strcpy(codenum[temp.lch],codenum[T[temp.lch].parent]);//编码计算
len1=strlen(codenum[temp.lch]);
codenum[temp.lch][len1]='0';
}
if(temp.rch!=-1)//查看是否有右子树
{
a[tail].lch=T[temp.rch].lch;
a[tail].rch=T[temp.rch].rch;
a[tail].loc=temp.rch;
tail++;
strcpy(codenum[temp.rch],codenum[T[temp.rch].parent]);//编码计算
len2=strlen(codenum[temp.rch]);
codenum[temp.rch][len2]='1';
}
}
if(temp.rch==-1&&temp.lch==-1)
{
printf("%c:",T[temp.loc].elem);//打印编码
puts(codenum[temp.loc]);
}
}
}
源代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 1000
typedef struct node
{
char elem;
float weight;
int loc;
int lch,rch,parent;
}Node;
int CalculateWeight(char a[],char b[],float weight[]);//输入字符串计算权重,返回字符串长度
Node *Huffmantree(char b[],float weight[],int len);//计算huffman树
void Codenum(Node T[],int l);//计算前缀编码并输出
int main()
{
char a[MAX]={'\0'},b[MAX]={'\0'};
float weight[MAX]={0};
int len;
Node *T;
printf("请输入需要编译的字符串(以输入回车为截止):\n");
gets(a);
len=CalculateWeight(a,b,weight);
T=Huffmantree(b,weight,len);
Codenum(T,len);
printf("以上为编码表\n");
return 0;
}
int CalculateWeight(char a[],char b[],float weight[])
{
int i=0,j;
int len1=0,len2=0;
while(a[i]!='\0')//计算输入字符的个数
{
i++;
}
len1=i;//记录输入字符的个数
i=0;
while(a[i]!='\0')//计算输入数据的权重
{
for(j=0;j<len2;j++)//判断已记录数据是否有该数据
{
if(a[i]==b[j])
{
i++;
weight[j]++;
break;
}
}
if(j==len2)//已记录数据不存在该字符则新增该字符
{
b[len2]=a[i];
weight[len2]++;
len2++;
i++;
}
}
for(i=0;i<len2;i++)
{
weight[i]=weight[i]/len1;//计算所占百分比
}
return len2;//返回不重复的字符数
}
Node *Huffmantree(char b[],float weight[],int len)
{
int i,j;
int p1=-1,p2=-1;
float small1=1,small2=1;
int Tlen;
Node *T;
T=(Node*)malloc((2*len-1)*sizeof(Node));//动态申请空间
Tlen=2*len-1;//记录二叉树的总结点个数
for(i=0;i<Tlen;i++)//初始化
{
T[i].elem='\0';
T[i].lch=-1;
T[i].rch=-1;
T[i].parent=-1;
T[i].weight=0;
}
for(i=0;i<len;i++)//叶结点的赋值
{
T[i].elem=b[i];
T[i].weight=weight[i];
}
for(j=len;j<Tlen;j++)//补充二叉树
{
for(i=0;i<len;i++)//遍历二叉树
{
if(T[i].parent==-1)//判断是否有父母
{
if(T[i].weight<small1)//寻找权重最小点
{
small2=small1;
p2=p1;
small1=T[i].weight;
p1=i;
}
else if(T[i].weight<small2)//寻找权重次小点
{
small2=T[i].weight;
p2=i;
}
}
}
T[j].weight=T[p1].weight+T[p2].weight;//生成父母
T[p1].parent=j;//二叉树关系的建立
T[p2].parent=j;
T[j].lch=p1;
T[j].rch=p2;
small1=1;
small2=1;
len++;//新增结点算入总长
}
return T;
}
void Codenum(Node T[],int l)
{
char codenum[MAX][MAX];//用于存储前缀编码
int top=0,tail=0;
int len=0,len1=0,len2=0;
Node *a;
Node temp;
memset(codenum,0,sizeof(codenum));
len=2*l-1;
a=(Node*)malloc(len*sizeof(int));//用于充当队列
a[tail].lch=T[len-1].lch;//队首赋初值
a[tail].rch=T[len-1].rch;
tail++;//队尾+1
while(top!=tail)
{
if(len==1)
{
temp.lch=a[top].lch;
temp.rch=a[top].rch;
temp.loc=len-1;
codenum[len-1][0]='0';
top++;
}
else
{
temp.lch=a[top].lch;
temp.rch=a[top].rch;
temp.loc=a[top].loc;
top++;//出队操作
if(temp.lch!=-1)//查看是否有左子树
{
a[tail].lch=T[temp.lch].lch;
a[tail].rch=T[temp.lch].rch;
a[tail].loc=temp.lch;
tail++;
strcpy(codenum[temp.lch],codenum[T[temp.lch].parent]);//编码计算
len1=strlen(codenum[temp.lch]);
codenum[temp.lch][len1]='0';
}
if(temp.rch!=-1)//查看是否有右子树
{
a[tail].lch=T[temp.rch].lch;
a[tail].rch=T[temp.rch].rch;
a[tail].loc=temp.rch;
tail++;
strcpy(codenum[temp.rch],codenum[T[temp.rch].parent]);//编码计算
len2=strlen(codenum[temp.rch]);
codenum[temp.rch][len2]='1';
}
}
if(temp.rch==-1&&temp.lch==-1)
{
printf("%c:",T[temp.loc].elem);//打印编码
puts(codenum[temp.loc]);
}
}
}