
#include<stdio.h>
#include<stdlib.h>
#define MAX 100
typedef struct node{
int w;
struct node *lchild,*rchild;
}BiTNode, *BiTree;
BiTree CreateHufferman(int num[], int n);
int GetWPL(BiTree T, int pathLen);
void GetCode(BiTree T, int pathLen);
int main() {
/*
5
2 5 7 9 13
*/
int n,num[MAX];
BiTree HfmTree;
int i;
int tmp;
// 输入个数
do{
printf("权重个数,最多能输入%d个\n>>> ", MAX);
scanf("%d", &n);
} while (n>MAX); //检查输入是否合法
// 输入数组
printf("输入权重数组(%d个)\n>>> ", n);
for (i=0; i<n; i++) {
scanf("%d", &num[i]);
}
// 创造
HfmTree = CreateHufferman(num, n);
// 计算WPL
tmp = GetWPL(HfmTree, 0); //根结点的路径长度为0
printf("\nWPL:%d\n", tmp);
// 哈夫曼编码
printf("权重\t哈夫曼编码");
GetCode(HfmTree, 0); //根结点的路径长度为0
printf("\n");
return 0;
}
BiTree CreateHufferman(int num[], int n) {
BiTree *tmp; //BiTree[]用于存放n个子树
BiTNode p; //结点
int k1,k2; //k1为最小的下标,k2为次小的下标
int i,j;
//创建一个BiTree[]来存n个子树
tmp = (BiTree *)malloc(sizeof(BiTree) * n);
//创建n个结点,每个结点即是树的根,放到tmp[]中统一管理
for (i=0; i<n; i++) {
tmp[i] = (BiTNode *)malloc(sizeof(BiTNode)); if (!tmp[i]) exit(0);
tmp[i]->w = num[i];
tmp[i]->lchild = tmp[i]->rchild = NULL;
}
//构造哈夫曼树,循环n-1次
for (i=1; i<n; i++) {
//找出tmp[0]至tmp[n]中的前两个
k1 = -1; //k1未选
for (j=0; j<n; j++) {
if (tmp[j]!=NULL && k1==-1) { //找到了第一个
k1 = j;
continue; //找k2
}
if (tmp[j]!=NULL) { //找到了第二个
k2 = j;
break; //退出
}
}
//找出最小的、次小的结点
for (j=k2; j<n; j++) { //从k2开始
if (tmp[j]==NULL) continue; //空树,进入下一轮循环
// 和当前k1、k2比较
if (tmp[j]->w < tmp[k1]->w) { //先和最小的k1比较
// 即 [j] < [k1],j是当前的最小
k2 = k1; //△原来最小的变成了次小
k1 = j; //最小的变成了j
} else if (tmp[j]->w < tmp[k2]->w) { //和次小的比较
// 即[k1] < [j] < [k2]
k2 = j; //次小的为j
}
}
//合并k1,k2
p = (BiTNode *)malloc(sizeof(BiTNode)); if (!p) exit(0);
p->w = tmp[k1]->w + tmp[k2]->w;
p->lchild = tmp[k1];
p->rchild = tmp[k2];
tmp[k1] = p; // 新结点的放到k1的位置
tmp[k2] = NULL; // k2位置为空
}
free(tmp); //删除动态建立的数组tmp[]
//它只是一个BiTNode *的指针数组,而所指结点(即新建的哈夫曼结点)是不会被删除的!
return p; //返回哈夫曼树的根结点
}
int GetWPL(BiTree T, int pathLen) {
// 叶子结点
if (T->lchild==NULL && T->rchild==NULL) {
return T->w * pathLen;
}
return GetWPL(T->lchild, pathLen+1) + GetWPL(T->rchild, pathLen+1);
}
void GetCode(BiTree T, int pathLen) {
static char tmp[2*MAX-1]; //存储编码的结果
int i;
// 叶子结点
if (T->lchild==NULL && T->rchild==NULL) {
printf("\n%d\t", T->w); //结点值
for (i=0; i<pathLen; i++) { //编码值
printf("%c", tmp[i]);
}
return ;
}
//往左走
tmp[pathLen] = '0';
GetCode(T->lchild, pathLen+1);
//往右走
tmp[pathLen] = '1';
GetCode(T->rchild, pathLen+1);
}