- 哈弗曼树的创建
- 带权路径长度的计算
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include <iomanip>
using namespace std;
typedef struct{
//定义节点的结构体
int weight;//权重
int parent, lChild, rChild;//双亲节点的下标、左孩子下标、右孩子下标
}HTNode, *HuffmanTree;
//选择所有节点中权重最小的两个节点的下标
void SelectMin(HuffmanTree hT, int n, int &s1, int &s2)
{
s1 = s2 = 0;
int i;
for(i = 1; i < n; i++)
{
// 首先找到两个没有双亲节点的节点下标
if(hT[i].parent == 0)
{
if(0 == s1)
{
s1 = i;
}
else
{
s2 = i;
break;
}
}
}
if(hT[s1].weight > hT[s2].weight)
{
// 保证s1所指节点的权重小于s2所指节点的权重
int t = s1;
s1 = s2;
s2 = t;
}
for(i+=1; i < n; i++)
{
if(hT[i].parent == 0)
{
/*
遍历没有双亲节点的所有节点
找到的节点权重如果比s1所指节点权重小,则更新s1节点让其指向当前节点
保证s1指向的权重最小的节点
*/
if(hT[i].weight < hT[s1].weight)
{
s2 = s1;
s1 = i;
}
else if(hT[i].weight < hT[s2].weight)
{
/*
如果当前节点的权重大于s1所指节点的权重,但是小于s2所指节点的权重
那么更新s2节点,让其指向当前节点
保证s2指向的除了s1之外最小的节点
*/
s2 = i;
}
}
}
}
void CreateHuffmanTree(HuffmanTree &ht)
{
// 8 5 29 7 8 14 23 3 11
// n:表示要构造的哈夫曼树的叶子节点个数
// m:表示所有节点的个数
int n, m;
// 输入叶子节点的个数
cin>>n;
m = 2 * n - 1;
// 构造m+1个节点,其中下标为0的不用
ht = (HuffmanTree)malloc((m+1) * sizeof(HTNode));
for(int i = 1; i <= m; i++)
{
/*
初始化所有节点的孩子节点和双亲节点为0
*/
ht[i].parent = 0;
ht[i].lChild = 0;
ht[i].rChild = 0;
}
for(int i = 1; i <= n; i++)
{
cin>>ht[i].weight;
}
// 第一个节点的权重存储所有节点的个数
ht[0].weight = m;
/***********初始化完成,开始构建哈夫曼树**********/
for(int i = n + 1; i <= m; i++)
{
// i表示现已有节点个数+1 ,新合成的节点就放在i的位置上
int s1, s2;
SelectMin(ht, i, s1, s2);
/*
s1和s2所指节点构成新的节点放在i的位置上
更新i的左孩子为s1,右孩子为s2,权重为s1的权重加上s2的权重
更新s1和s2的双亲节点为i
*/
ht[s1].parent = ht[s2].parent = i;
ht[i].lChild = s1;
ht[i].rChild = s2;
ht[i].weight = ht[s1].weight + ht[s2].weight;
}
}
int HuffmanTreeWPL_(HuffmanTree hT, int i, int deepth)
{
/*
递归计算某个节点的带权路径
*/
if(hT[i].lChild == 0 && hT[i].rChild == 0)
{
return hT[i].weight * deepth;
}
else
{
return HuffmanTreeWPL_(hT, hT[i].lChild, deepth+1) + HuffmanTreeWPL_(hT, hT[i].rChild, deepth+1) ;
}
}
int HuffmanTreeWPL(HuffmanTree hT)
{
// 返回整棵树的带权路径长度 WPL
return HuffmanTreeWPL_(hT, hT[0].weight, 0);
}
void Print(HuffmanTree hT)
{
cout << "index weight parent lChild rChild" << endl;
cout << left; // 左对齐输出
for(int i = 1, m = hT[0].weight; i <= m; ++ i){
//setw()函数表示固定输出字符的长度
cout << setw(5) << i << " ";
cout << setw(6) << hT[i].weight << " ";
cout << setw(6) << hT[i].parent << " ";
cout << setw(6) << hT[i].lChild << " ";
cout << setw(6) << hT[i].rChild << endl;
}
}
void DestoryHuffmanTree(HuffmanTree &hT)
{
//销毁哈夫曼树
free(hT);
}
int main()
{
HuffmanTree hT;
CreateHuffmanTree(hT);
Print(hT);
cout << "WPL = " << HuffmanTreeWPL(hT) << endl;
DestoryHuffmanTree(hT);
return 0;
}
运行结果如下: