哈夫曼树的基本概念
路径:从树中结点到另一个结点之间的分支构成这两个结点间的路径
结点的路径长度:两结点间路径上的分支数
树的路径长度:从树根到每一个结点的路径长度之和。记作:TL
权:将树中结点赋给一个有着某种特殊意义的值,则这个数值称为该结点的权
结点的带权路径长度:从根结点出发到该节点之间的路径长度与该结点的权的乘积
树的带权路径长度:树中所有叶子结点的带权路径长度之和
哈夫曼树:最优树(带权路径长度(WPL)最短的树)
哈夫曼树的特点
满二叉树不一定是哈夫曼树
哈夫曼树中权值越大的叶子离根越近
具有相同带权结点的哈夫曼树不唯一
哈夫曼树的一些知识点
- 包含n个叶子结点的哈夫曼树共有2n-1个结点
- 哈夫曼树的结点的度为0和2,没有度为1的结点
- 包含n棵树的森林要经过n-1次合并才能形成哈夫曼树,共产生n-1个新结点
哈夫曼树构造算法的实现
定义结构体
typedef struct{
int weight;
int parent,lch,rch;
}HTNode,*HuffmanTree;
算法实现
void Select(HuffmanTree &ht, int i, int &s1, int &s2) {
int min = INT32_MAX;
for (int j = 1; j <=i; ++j) {
for (int k = 1; k <=i; ++k) {
int temp = ht[j].weight + ht[k].weight;
if (k != j && ht[j].parent == 0 && ht[k].parent == 0) {
if (temp < min) {
min = temp;
s1 = j;
s2 = k;
}
}
}
}
}
void createHuffmanTree(int n) {
int m = 2 * n - 1;
HuffmanTree ht = new HTNode[m + 1];
for (int i = 1; i <= m; ++i) {
ht[i].parent = ht[i].lch = ht[i].rch = 0;
}
for (int j = 1; j <= n; ++j) {
cin >> ht[j].weight;
}
for (int k = n + 1; k <= m; ++k) {
int s1, s2;
Select(ht, k - 1, s1, s2); // 取权值相加最小的两个结点
ht[s1].parent = ht[s2].parent = k; // 他们俩的父节点就是构造出来的新结点(两个权值的和)
ht[k].lch = s1; // 新结点左孩子赋值
ht[k].rch = s2; // 新结点右孩子赋值
ht[k].weight = ht[s1].weight + ht[s2].weight; // 权值相加
}
for (int l = 1; l <= m; ++l) {
cout << "weight :" << ht[l].weight<<" " << "parent : "
<< ht[l].parent << " " << "lchild: "
<< ht[l].lch << " " << "rchild :"
<< ht[l].rch<< " " << endl;
}