最优二叉树
权值
:是对叶子结点赋予的一个有意义的数值量。
带权路径长度
:从根结点到各个叶子结点的路径长度与相应叶子结点权值的乘积之和称为二叉树的带权路径长度
最优二叉树
:带权路径长度最小的二叉树称为最优二叉树,也称哈夫曼树
代码实现
#include <iostream>
using namespace std;
//具有n个叶子节点的哈夫曼树有n-1个分支节点,因此哈夫曼树一共有2n-1个节点
struct ElemType
{
int weight;//假定权值为整数
int parent, lchild, rchild;//游标
};
class HuffmanTree
{
public:
HuffmanTree(int w[], int n);
HuffmanTree();
void Print();
private:
ElemType* huffTree;
int num;
void Select(int n, int& i1, int& i2);
};
HuffmanTree::HuffmanTree(int w[], int n)
{
int i1, i2;
huffTree = new ElemType[2 * n - 1];
num = n;
//初始化所有结点没有双亲和孩子
for (int i = 0; i < 2*num-1; i++)//2*num-1而非n
{
huffTree[i].lchild = -1;
huffTree[i].parent = -1;
huffTree[i].rchild = -1;
}
//初始化叶子节点的权值
for (int i = 0; i < n; i++)
{
huffTree[i].weight = w[i];
}
//连接 n-1次合并
for (int i = n; i < 2 * num - 1; i++)
{
Select(i, i1, i2);//返回最小两个值的下标i1, i2
huffTree[i].weight = huffTree[i1].weight + huffTree[i2].weight;
huffTree[i1].parent = i;
huffTree[i2].parent = i;
huffTree[i].lchild = i1;
huffTree[i].lchild = i2;
//错误写法 父亲和儿子赋值成对应下标而不是值
//huffTree[i1].parent = huffTree[i].weight;
//huffTree[i2].parent = huffTree[i].weight;
//huffTree[i].lchild = huffTree[i1].weight;
//huffTree[i].lchild = huffTree[i2].weight;
}
}
void HuffmanTree::Print()
{
int i, k;
cout << "每个叶子到根结点的路径是:" << endl;
for (i = 0; i < num; i++)
{
cout << huffTree[i].weight;
k = huffTree[i].parent;
while (k != -1)
{
cout << "-->" << huffTree[k].weight;
k = huffTree[k].parent;
}
cout << endl;
}
}
void HuffmanTree::Select(int n, int& i1, int& i2)
{
int i = 0, temp;
for (; i < n; i++)
{
if (huffTree[i].parent == -1)
{
i1 = i;
break;
}
}
for (i = i+1; i < n; i++)
{
if (huffTree[i].parent == -1)
{
i2 = i;
break;
}
}
if (huffTree[i1].weight > huffTree[i2].weight)
{
temp = i1;
i1 = i2;
i2 = temp;
}
for (i = i + 1; i < n; i++)
{
if (huffTree[i].parent == -1)
{
if (huffTree[i].weight < huffTree[i1].weight)
{
i2 = i1;
i1 = i;
}
else if (huffTree[i].weight < huffTree[i2].weight)
{
i2 = i;
}
}
}
}
int main()
{
int w[] = { 2, 3, 4 ,5 };
HuffmanTree T{ w, 4 };
T.Print();
return 0;
}
介绍一下Select函数:实现查找最小的两个权值的下标,因为返回值是两个,所以函数参数为引用。
前两个for循环分别标记出没有父亲结点的数组下标,if语句目的在让i1始终保持是权值较小的那个的下标。最后一个for循环遍历剩下的权值寻找最小的结点。强调一下初始值i=i+1,否则i1和i2可能会被重复选择。
选择最小的节点的过程类似于选择排序
,每次找到最小元素更新到i1和i2中。
下面是代码中值得注意的地方:
1.哈夫曼树一共有2n-1个节点,因此在创建huffTree数组时应该开辟2n-1个ElemType类型的空间。
2.对于节点之间的连接,可以通过记录父亲和孩子节点的下标来完成。在连接时需要注意将相应节点的parent、lchild、rchild属性赋值正确。