【哈夫曼树】用优先队列优化哈夫曼树的构建(严书版数组父亲孩子法)
严书代码思路:
哈夫曼树n个叶子节点的话必然是2n-1。
(1)用H数组的前n位(1~n)存这n个节点(权重, 父亲下标,左孩子下标,右孩子下标);
(2)从i=n+1的位置开始,每次从前面选两个权重最小的,把它们的权重和放到i位置,并修改挑出来的两个结点的父亲下标为i,i结点的左孩子下标和右孩子下标为两个结点的下标;
(3)重复(2),至i加到2n-1为止。
这个算法要是每次都用O(n)的线性遍历去找两个最小的话,复杂度是O(n²)的,这个过程可以用小顶堆优化,复杂度降为O(nlogn)
代码
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1000, MAX_M = 2005;
struct node {
int w;
int parent, lchild, rchild;
};
typedef pair<int, int> P;//(权重, 下标)
int n,m;
int W[MAX_N];
node H[MAX_M];//父亲孩子法
//原理:用H数组前n位存叶子节点,之后的n-1位存它们的父节点
void mkHuff(){
priority_queue<P, vector<P>, greater<P> > que;//按权重做小顶堆, 不过主要目的是在pop时得到在H数组中的下标
for(int i = 0;i < n;i++){
P no = {W[i],i};
que.push(no);
H[i] = {W[i], -1, -1, -1};//初始化三个指针都为-1
}
for(int i = n;i < m;i++){
//取出两个最小的下标
int pos1 = que.top().second;que.pop();
int pos2 = que.top().second;que.pop();
node newno = {H[pos1].w + H[pos2].w, -1, pos1, pos2};
H[pos1].parent = i;
H[pos2].parent = i;
H[i] = newno;
que.push({H[pos1].w + H[pos2].w, i});
}
}
int main(){
cin>>n;
m = 2*n-1;
//输入0到n-1这n个数的权重
for(int i = 0;i < n;i++){
cin>>W[i];
}
mkHuff();
for(int i = 0;i < m;i++){
cout<<H[i].w<<' '<<H[i].parent<<' '<<H[i].lchild<<' '<<H[i].rchild<<endl;
}
return 0;
}
/*
5
3 5 1 4 2
*/
输出: