关于哈夫曼树的讲解请参考上篇《三步学通哈夫曼树》(https://blog.csdn.net/helloworldchina/article/details/105210054),这里笔者仅补充一下C++代码的实现。见下:
1 c++代码
#include <iostream>
#include <iostream>
#include <iomanip>
using namespace std;
bool pr=false;//true 打印测试日志
//哈夫曼树的结构
typedef struct
{
int weight; // 权值
int parent, lChild, rChild; // 双亲及左右孩子的下标
}HTNode, *HuffmanTree;
//输出哈夫曼树各结点信息
void Print(HuffmanTree hT)
{
std::cout << "index weight parent lChild rChild" << std::endl;
std::cout << left; // 左对齐输出
for(int i = 1, m = hT[0].weight; i <= m; i++)
{
std::cout << setw(5) << i << " ";
std::cout << setw(6) << hT[i].weight << " ";
std::cout << setw(6) << hT[i].parent << " ";
std::cout << setw(6) << hT[i].lChild << " ";
std::cout << setw(6) << hT[i].rChild << std::endl;
}
}
// 选择权值最小的两颗树
void SelectMin(HuffmanTree hT, int k, int &index1, int &index2)
{
index1 = index2 = 0;
int i,j;
for(j = 1; j <= k;j++)
{//使index1,index2分别指向hT中最前面的两个无双亲的结点
if(0 == hT[j].parent)
{
if( 0== index1)
{
index1 = j;
}
else
{
index2 = j;
break;
}
}
}
if(hT[index1].weight > hT[index2].weight)
{//使结点index1的权小于index2的权
int t = index1;
index1 = index2;
index2 = t;
}
for(i =j+1; i<k; i++){//继续查找没有双亲且权值最小的两个结点,将其地址记在index1和index2中
if(0 == hT[i].parent)
{
if(hT[i].weight < hT[index1].weight)
{
index2 = index1;
index1 = i;
}else if(hT[i].weight < hT[index2].weight)
{
index2 = i;
}
}
}
}
// 构造有n个权值(叶子结点)的哈夫曼树
int CreateHufmanTree(HuffmanTree &hT)
{
std::cout << "请输入权值的数量n=? " << std::endl;
int n, k;//n 权值数(叶子结点数) k结点的个数
cin >> n;
if (n<=1) return 0;
k = 2*n - 1;
//创建存储哈夫曼树的数组
hT = new HTNode[k + 1]; // 0号结点不使用
//给数组赋初值0
for(int i = 1; i <= k; i++){
hT[i].parent = hT[i].lChild = hT[i].rChild = 0;
}
std::cout << "请依次输入权值,并回车确认" << std::endl;
for(int i = 1; i <= n; i++){
cin >> hT[i].weight; // 输入权值
}
hT[0].weight = k; // 用0号结点保存结点数量
if (pr)
{
std::cout << "打印初始的数组:" << std::endl;
Print(hT);
}
/****** 初始化完毕, 创建哈夫曼树 ******/
for(int i = n + 1; i <=k; i++)
{
int index1, index2;
SelectMin(hT, i, index1, index2);
hT[index1].parent = hT[index2].parent = i;
hT[i].lChild = index1; hT[i].rChild = index2; // 作为新结点的孩子
hT[i].weight = hT[index1].weight + hT[index2].weight; // 新结点为左右孩子结点权值之和
if (pr)
{
std::cout << "打印构建哈夫曼树过程中的数组:" << std::endl;
std::cout << "i=" <<i<<std::endl;
std::cout << "index1=" <<index1<<";index2="<<index2<<std::endl;
Print(hT);
}
}
return 1;
}
int HuffmanTreeWPL_w(HuffmanTree hT, int i, int deepth)
{
if(hT[i].lChild == 0 && hT[i].rChild == 0)
{
return hT[i].weight * deepth;
}
else
{
return HuffmanTreeWPL_w(hT, hT[i].lChild, deepth + 1) + HuffmanTreeWPL_w(hT, hT[i].rChild, deepth + 1);
}
}
// 计算WPL(带权路径长度)
int HuffmanTreeWPL(HuffmanTree hT)
{
return HuffmanTreeWPL_w(hT, hT[0].weight, 0);
}
// 销毁哈夫曼树
void DestoryHuffmanTree(HuffmanTree &hT)
{
delete[] hT;
hT = NULL;
}
int main()
{
HuffmanTree hT;
if (CreateHufmanTree(hT))
{
std::cout << "打印哈夫曼树数组:" << std::endl;
Print(hT);
std::cout << "WPL = " << HuffmanTreeWPL(hT) << std::endl;
DestoryHuffmanTree(hT);
} else std::cout << "输入有误,不能创建哈夫曼树!" << std::endl;
return 0;
}
2 运行结果