//主要源代码如下
#include<stdio.h>
#include<malloc.h>
#define MAX_NUM 105
typedef struct {
int weight;
char ch;
int parent,lchild,rchild;
int visited;
}HTnode,*HTree;
void selectTwoMin(HTree &HT,int n,int &s1,int &s2){
int firMin=101,secMin=101;
for(int i=1;i<=n;i++)
if(!HT[i].visited&&HT[i].weight<=firMin){
firMin=HT[i].weight;//在没有被访问的结点中选择出最小的频率
s1=i;
}
HT[s1].visited=1;//将最小的频率对应的结点标记为已被访问
for(int i=1;i<=n;i++)//继续在没有被访问的结点中选择出次小的频率
if(!HT[i].visited&&HT[i].weight<=secMin){
secMin=HT[i].weight;
s2=i;
}
HT[s2].visited=1;//将次小的频率对应的结点标记为已被访问
}
int count;//全局变量,要进行编码的字符的个数。
void creatHuffmanTree(HTree &HT){
int m,w,s1,s2;char ch;
printf("请输入要进行编码的字符个数:");
scanf("%d",&count);
getchar();//吸收回车符号
printf("请输入%d个字符对应的频率(%%),如:a 30\n",count);
m=2*count-1;//哈夫曼树总结点个数
HT=(HTree)malloc((m+1)*sizeof(HTnode));//创建需要的所有节点
for(int i=1;i<=count;i++){//对count个叶子结点输入字母和对应的频率
scanf("%c%d%*c",&ch,&w);//%*c用于吸收回车字符
HT[i].ch=ch;
HT[i].weight=w;
HT[i].visited=0;//初始都标记没有被访问过
}
for(int i=count+1;i<=m;i++){//对剩下的非叶子结点进行初始化
HT[i].ch='0';
HT[i].lchild=HT[i].rchild=HT[i].parent=HT[i].weight=HT[i].visited=0;
}
for(int i=count+1;i<=m;i++){ //创建哈夫曼树
selectTwoMin(HT,i-1,s1,s2);//得到最小频率下标s1,次小频率下标s2
HT[s1].parent=i;//第i个结点为s1和s2对应结点的父母
HT[s2].parent=i;
HT[i].lchild=s1;//第i个结点的左右孩子分别为s1和s2对应的结点
HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;//更新第i个结点的频率
}
}
void huffmanCoded(HTree &HT){ //哈夫曼编码
char HC[MAX_NUM];
int j;
for(int i=1;i<=count;i++){//遍历1到count个的叶子结点,输出其哈夫曼编码
j=0;//用于在HC数组中存编码的指针
printf("字母%c的哈夫曼编码为:",HT[i].ch);
//初始条件:当前结点为第i个叶子结点,当前父母为第i个叶子结点的父母
//循环条件:parent!=0,即走到根结点结束编码
//控制条件:将当前结点的父母为下次循环的当前结点,将当前父母的父母为下次循环的父母
for(int cur=i,parent=HT[i].parent;parent!=0;cur=parent,parent=HT[parent].parent)
if(HT[parent].lchild==cur) HC[j++]='0';//左孩为0
else HC[j++]='1'; //右孩为1
for(int k=j-1;k>=0;k--) //逆序输出得到哈夫曼编码
printf("%c",HC[k]);
printf("\n");
}
}
int main(){
HTree HT;
creatHuffmanTree(HT);
huffmanCoded(HT);
return 0;
}
/*
m 13
n 44
o 12
p 17
q 9
r 5
*/