#include<stdio.h>
#include<stdlib.h>
#define leafNumber 20 //默认权值集合大小
#define totalNumber 39 //数结点个数=2*leafNumber-1
typedef struct {
char data; //结点的值
int weight; //结点的权
int Parent,lchild,rchild; //双亲、左、右子女结点指针
}HTNode;
typedef struct {
char elem[totalNumber]; //Huffman树存储数组
int num; //num是外结点数,root是根
}HFTree;
//算法
void createHFTree (HTNode HT[],HFTree HElem[],char value[],int fr[],int n){
//输入数据value[n]和相应权值fr[n],构造用三叉链表表示的Huffman树HT
for(int i = 0;i<n;i++){
HT[i].data = value[i];
HElem[i].elem[i] = fr[i];
}
int i,k,s1,s2;
int min1,min2;
for(i = 0;i<leafNumber;i++) //所有指针置空
HT[i].Parent = HT[i].lchild = HT[i].rchild = -1;
for(i = n;i<2*n-1;i++){ //逐步构造Huffman树
min1 = min2 = 0x7fff; //min1是最小值,min2是次小值
s1 = s2 = 0; //s1是最小值点,s2是次小值点
for(k = 0;k<i;k++) //构造Huffman树的过程
if(HT[k].Parent == -1) //未成为其他树的子树
if(HT[k].weight<min1){ //新的最小值
min2 = min1;
s2 = s1; //原来的最小值变成次小值
min1 = HT[k].weight; //记忆新的最小值
s1 = k;
}else if(HT[k].weight<min2){ //新的次小值
min2 = HT[k].weight;
s2 = k;
}
HT[s1].Parent=HT[s2].Parent=i; //构造子树
HT[i].lchild=s1;
HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
}
}
//建立Huffman编码
void createMessage(HTNode HT[],HFTree HElem[],int n){
HFTree d;
int i,c,f;
for(i=0;i<n;i++)
{
d.num=n;
c=i;
f=HT[i].Parent;
while(f!=0)
{
if(HT[f].lchild==c)
d.elem[--d.num]='0';
else
d.elem[--d.num]='1';
c=f;
f=HT[f].Parent;
}
HElem[i]=d;
}
}
//输出Huffman编码
void printMessage (HTNode HT[],HFTree HElem[],int n) {
printf("输出huffman编码:\n");
for(int i=0;i<n;i++)
{
printf("%c\n",HT[i].data);
for(int k=HElem[i].num;k<n;k++)
printf("%c",HElem[i].elem[k]);
printf("\n\n");
}
}
main(){
HTNode HT[2*leafNumber];
HFTree HElem[leafNumber],d;
int n,b[n]; //所需要的数据个数
printf("请输入需要编码的元素个数(1->%d):",leafNumber);
scanf("%d",&n);
if(n>leafNumber||n<1)
return 1;
char a[n];
for(int i = 0;i<n;i++){
fflush(stdin);
printf("\n请输入第%d位的结点值:",i+1);
scanf("%c",&a[i]);
printf("\n请输入第%d位权值:",i+1);
scanf("%d",&b[i]);
}
createHFTree(HT,HElem,a,b,n);
createMessage(HT,HElem,n);
printMessage(HT,HElem,n);
}