1 哈夫曼树的概念
在许多应用中经常将树中的节点赋予一个权值 , 从根节点到该节点之间的路径长度与该节点上的权值的乘积称为该节点的带权路径长度(WPL) , 树中所有叶子节点的带权路径长度之和称为该树的带权路径长度。
.其中no为叶节点的个数,wi和li分别表示第 i 个叶节点权值和根到它之间的路径长度 。
在
个带权叶节点构成的所有二叉树中,带权路径长度最小的称为哈夫曼树或者最优二叉树 。
如下图为一哈夫曼树示意图。
2、构造哈夫曼树
假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为:
(1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);
(2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
(3)从森林中删除选取的两棵树,并将新树加入森林;
(4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。
如:对 下图中的六个带权叶子结点来构造一棵哈夫曼树,步骤如下:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std ;
const int MAX = 1015 ;
typedef struct {
char data ;
int weight ;
int parent ;
int lchild ;
int rchild ;
}HTNode;
int n ;
void CreateHT(HTNode *ht , int n)
{
int lnode , rnode ;
double min1 ,min2 ;
for(int i = 0 ; i<2*n-1 ;i++) // 所有节点的相关域初值未 -1
ht[i].parent = ht[i].lchild = ht[i].rchild = -1 ;
for(int i = n ; i<2*n - 1 ;i++)
{
// 将每个非叶子节点放到 n ~ 2n-2 中
min1 = min2 = 99999 ;
lnode = rnode = -1 ;
// 每次在 ht[0...i-1] 中选取权值最小的两个节点
for(int k = 0 ; k<=i-1;k++)
if(ht[k].parent == -1) // 在尚未构造二叉树的节点中查找
{
if(ht[k].weight <min1)
{
min2 = min1 ;
rnode = lnode ;
min1 = ht[k].weight ;
lnode = k ;
}
else if (ht[k].weight <min2 )
{
min2 = ht[k].weight ;
rnode = k ;
}
}
ht[i].weight = ht[lnode].weight + ht[rnode].weight ; // h[i]作为双亲
ht[i].lchild = lnode ;
ht[i].rchild = rnode ;
ht[lnode].parent = i ;
ht[rnode].parent = i ;
}
}
int main()
{
int n ;
HTNode h[MAX] ;
cin >>n ;
for(int i = 0 ; i<n ;i++)
cin >> h[i].weight;
CreateHT(h,n);
for(int i = 0 ; i<2*n-1 ;i++)
cout<<h[i].weight <<" ";
return 0 ;
}
标签:weight,哈夫曼,int,ht,构造,权值,节点 From: https://blog.51cto.com/u_15970235/6064294