问题描述
假设用于通信的电文由n个字符组成,字符在电文中出现的频度(权值)为w1,w2,…,wn,试根据该权值序列构造哈夫曼树,并计算该树的带权路径长度。
输入说明
第1行为n的值,第2行为n个整数,表示字符的出现频度。
输出说明
输出所构造哈夫曼树的带权路径长度。
输入样例
8
7 19 2 6 32 3 21 10
输出样例
261
- 采用顺序存储方式构造哈夫曼树,也是教材上的源码,稍作修改。
- 本题只关注parent,weight和depth即可,不涉及左右孩子。
- 采用动态分配数组空间,不浪费
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#define Max 0x7fffffff
typedef struct {
int weight;
int parent;//取-1表示无父
}HTNode;
void Huffman(HTNode *tree,int n){
int m; //叶子结点数,总结点数
m=2*n-1;
int i,j,p1,p2;
int small1,small2,f;
for(i=n;i<m;i++){
//进行n-1次合并,产生n-1个新结点
p1=p2=0;//存放最小值和次小值的下标
small1=small2=Max; //最小权值,次小权值
for(j=0;j<i;j++){
if(tree[j].parent == -1){//判断是否合并过
if(tree[j].weight<small1){
small2=small1;//原最小变次小
small1=tree[j].weight;
p2 = p1;
p1 = j;
}
//这两个if语句的顺序很必要
else if(tree[j].weight<small2){
small2 = tree[j].weight;
p2 = j;
}
}
}
//修改合并后的信息
tree[p1].parent = i;
tree[p2].parent = i;
tree[i].parent = -1;
tree[i].weight = tree[p1].weight + tree[p2].weight;
}
}
int main(){
int n,m,i,j;//叶子数,总结点个数
scanf("%d",&n);
HTNode *tree = (HTNode*)malloc((2*n-1)*sizeof(HTNode));
for(i=0;i<2*n-1;i++){//初始化
tree[i].parent = -1;
tree[i].weight = 0;
}
for(i=0;i<n;i++)
scanf("%d",&tree[i].weight);
Huffman(tree,n);
//计算深度,就是看parent还有几步到-1
int len=0;
for(i=0;i<n;i++){
int depth=0,k=tree[i].parent;
while(k != -1){
depth++;
k = tree[k].parent;
}
len += (tree[i].weight)*depth;
}
printf("%d",len);
free(tree);
return 0;
}
感谢观看,欢迎指正~