#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MaxSize 100
typedef struct HTNode{//定义哈夫曼树结点
int weight;
int parent,lchild,rchild;
}HTNode,*HuffmanTree;
typedef char** HuffmanCode;//定义哈夫曼编码的指针类型,用二级指针管理各叶子节点对应的哈夫曼编码字符串
void Select(HuffmanTree HT,int n,int &s1,int &s2){//定义函数选出权重最小的两个结点索引s1,s2
int min1=0,min2=0;
for(int i=0;i<=n;i++){
if(HT[i].parent==0){//如果当前结点i无父节点
if(min1==0){//第一次找到无父的结点,将其索引赋给min1
min1=i;
}else if (min2==0){//第二次找到无父的结点,将其索引赋给min2,并调整min1指向的节点权重小于min2
min2=i;
if(HT[min1].weight > HT[min2].weight){
int temp=min1;
min1=min2;
min2=temp;
}
}else{//已经找到两个无父结点,继续查找比较
if(HT[i].weight < HT[min1].weight){//如果当前找到的无父结点权重比min1小,将min1赋给min2,当前结点索引赋给min1,保证目前找到的两个小无父结点min1<min2
min2=min1;
min1=i;
}else if(HT[i].weight < HT[min2].weight){//如果当前无父结点大于min1,小于min2,将其索引赋给min2
min2=i;
}
}
}
}
s1=min1;
s2=min2;
}
void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int w[],int n){//构建哈夫曼树和哈夫曼编码
if(n<=1) return;
int m=2*n-1;//哈夫曼树结点总数
HT=(HTNode*)malloc((m+1)*sizeof(HTNode));//分配哈夫曼树结点数组内存空间,多分配一个方便下标从1开用
for(int i=1;i<=n;i++){
HT[i].weight=w[i];
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;
}
for(int i=n+1;i<=m;i++){//构建哈夫曼树
int s1,s2;
Select(HT,i-1,s1,s2);//选出权值最小的两个结点
HT[i].weight=HT[s1].weight+HT[s2].weight;//新结点权重
HT[s1].parent=i;
HT[s2].parent=i;
HT[i].lchild=s1;
HT[i].rchild=s2;
}
HC=(HuffmanCode)malloc((n+1)*sizeof(char));//分配哈夫曼编码数组内存,存指向每个叶结点编码的指针
char *temp=(char*)malloc(n*sizeof(char));//n个叶结点时,最长的哈夫曼编码有n-1位,此处添加一个结束符
temp[n-1]='\0';//结束符
int start,pos,parent;
for(int i=1;i<=n;i++){
start=n-1;//编码的起始位置初始化为临时编码的最后一位,结束符的位置
pos=i;
parent=HT[i].parent;
while (parent!=0){//沿父结点路径回溯到根结点,直到没有父结点
if(HT[parent].lchild==pos){
temp[--start]='0';
}else{
temp[--start]='1';
}
pos=parent;
parent=HT[parent].parent;
}
HC[i]=(char*)malloc((n-start)*sizeof(char));//给每个叶结点分配各自实际编码长度的空间
strcpy(HC[i],&temp[start]);//将临时编码数组,从start开始复制到HC[i]
}
free(temp);
}
void printHTandHC(HuffmanTree HT,HuffmanCode HC,int n){//输出哈夫曼树和编码
printf("哈夫曼树结点信息:\n");
for(int i=1;i<=2*n-1;i++){
printf("编号:%d,权重:%d,父:%d,左子:%d,右子:%d\n",i,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
}
printf("哈夫曼编码:\n");
for(int i=1;i<=n;i++){
printf("权重:%d,编码:%s\n",HT[i].weight,HC[i]);
}
}
int main(){
int n;
int w[MaxSize];
HuffmanTree HT;
HuffmanCode HC;
printf("叶结点数:");
scanf("%d",&n);
for(int i=1;i<=n;i++){
printf("请输入第%d个结点的权值:",i);
scanf("&d",&w[i]);
}
HuffmanCoding(HT,HC,w,n);
printHTandHC(HT,HC,n);
return 0;
}