问题描述
假设用于通信的电文由n个字符组成,字符在电文中出现的频度(权值)为w1,w2,…,wn,试根据该权值序列构造哈夫曼树,并计算该树的带权路径长度。
输入说明
第1行为n的值,第2行为n个整数,表示字符的出现频度。
输出说明
输出所构造哈夫曼树的带权路径长度。
输入样例
8
7 19 2 6 32 3 21 10
输出样例
261
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int weight,lenth,parent,lchild,rchild;
}hfmtree;
hfmtree tree[100];
void hfm(hfmtree tree[],int n)
{
int i,j,p1,p2,s1,s2,d,len,all;
hfmtree s;
for(i=0;i<2*n-1;i++)
{//对哈夫曼树的各个结点进行初始化,所有权值为零,-1表示没有父结点和子结点
tree[i].parent=-1;tree[i].lchild=-1;
tree[i].rchild=-1;tree[i].weight=0;
}
for(i=0;i<n;i++)
{//输入前n个结点的权值
scanf("%d",&d);
tree[i].weight=d;
}
for(i=n;i<2*n-1;i++)
{//进行n-1次合并,产生n-1个新结点
p1=-1;p2=-1;s1=1000;s2=1000;//s1和s2分别表示最小值和次小值
for(j=0;j<i;j++)
{//寻找每次需要合并的结点中权值最小和次小的结点
if(tree[j].parent==-1)
{
if(tree[j].weight<s1)
{
s2=s1;s1=tree[j].weight;
p2=p1;p1=j;
}
else if(tree[j].weight<s2)
{
s2=tree[j].weight;
p2=j;
}
}
}
tree[p1].parent=i;tree[p2].parent=i;
tree[i].lchild=p1;tree[i].rchild=p2;
tree[i].weight=tree[p1].weight+tree[p2].weight;//两结点合并
}
all=0;//以下为计算并输出所构造哈夫曼树的带权路径长度的过程
for(i=0;i<n;i++)
{
len=0;
s=tree[i];
while(s.parent!=-1)
{
s=tree[s.parent];
len++;
}
tree[i].lenth=len;
all+=tree[i].weight*tree[i].lenth;
}
printf("%d",all);
}
int main()
{
int n,i;
scanf("%d",&n);
hfm(tree,n);
return 0;
}