数据结构(哈夫曼树)
原文引用:https://www.jianshu.com/p/b9352dd3f406?from=bdhd_site
1. 哈夫曼树的基本概念
哈夫曼树又称最优树,是一类带权路径长度最短的树。
路径:从树中一个结点到另一个结点之间的分支构成这两个结点之间的路径。
路径长度:路径上的分支数目称作路径长度。
树的路径长度:从树根到每一结点的路径之和。
权:赋予某个实体的一个量,是对实体的某个或某些属性的数值描述。在数据结构中,实体有结点(元素)和边(关系)两大类,所以对应有结点权和边权。
结点的带权路径长度:从该结点到树根之间的路径长度与结点上权的乘积。
树的带权路径长度:树中所有叶子结点的带权路径长只和。
哈夫曼树:假设有m个权值{w1,w2,w3,...,wn},可以构造一棵含有n个叶子结点的二叉树,每个叶子结点的权为wi,则其中带权路径长度WPL最小的二叉树称做最优二叉树或哈夫曼树。
![]()
2.哈夫曼树的构造算法
(1) 哈夫曼树的构造过程
(2) 哈夫曼树的实现
由于哈夫曼树中没有度为1的结点,则一棵有n个叶子结点的哈夫曼树共有2n -1个结点,可以存储在一个大小为2n-1的一维数组中。
weight parent lchild rchild
// 选择权值最小的两颗树
void SelectMin(HuffmanTree hT, int n, int &s1, int &s2)
{
s1 = s2 = 0;
int i;
for(i = 1; i < n; ++ i){
if(0 == hT[i].parent){
if(0 == s1){
s1 = i;
}
else{
s2 = i;
break;
}
}
}
if(hT[s1].weight > hT[s2].weight){
int t = s1;
s1 = s2;
s2 = t;
}
for(i += 1; i < n; ++ i){
if(0 == hT[i].parent){
if(hT[i].weight < hT[s1].weight){
s2 = s1;
s1 = i;
}else if(hT[i].weight < hT[s2].weight){
s2 = i;
}
}
}
}
// 构造有n个权值(叶子节点)的哈夫曼树
void CreateHufmanTree(HuffmanTree &hT)
{
int n, m;
cin >> n;
m = 2*n - 1;
hT = new HTNode[m + 1]; // 0号节点不使用
for(int i = 1; i <= m; ++ i){
hT[i].parent = hT[i].lChild = hT[i].rChild = 0;
}
for(int i = 1; i <= n; ++ i){
cin >> hT[i].weight; // 输入前n个单元中叶子结点的权值
}
hT[0].weight = m; // 用0号节点保存节点数量
/****** 初始化完毕, 创建哈夫曼树 ******/
for(int i = n + 1; i <= m; ++ i){
//通过n-1次的选择、删除、合并来创建二叉树
int s1, s2;
SelectMin(hT, i, s1, s2);
hT[s1].parent = hT[s2].parent = i;
hT[i].lChild = s1; hT[i].rChild