哈夫曼树
在一棵树中,从任意一个结点到另外一个结点之间的通路称作路径,该路径上所需要经过的边的个数别称为该路径的长度。若树中结点带有表示某种意义的权值,那么从根结点到该结点的路径长度乘该结点的权值被称为该结点的带权路径长度。树中所有叶子结点的带权路径长度之和为该树的带权路径长度和。
给定n个结点和它们的权值,以它们为叶子结点构造一棵带权路径长度最小的二叉树,该二叉树即为哈夫曼树,也被称作最优二叉树。
给定结点的哈夫曼树可能不唯一。
哈夫曼算法
1、将所有结点放入集合K中。
2、若集合K中剩余的结点数目>=2,则取出其中权值最小的两个结点,构造它们同时为某个新结点的左右孩子,该新结点是它们的父结点,新结点的权值为孩子结点的权值之和。将父结点放入集合K中,重复步骤2、3。
3、若集合K中仅剩余一个结点,该结点即为构造出的哈夫曼树的根结点,所有构造得到的中间结点(即哈夫曼树上的所有非叶子结点)的权值之和为哈夫曼树的带权路径长度和。
实现:
为了方便高效地实现求得集合K中权值最小的两个元素,需要使用堆数据结构,STL中对应的模版为——优先级队列。
利用语句:
priority_queue<int> Q
建立一个保存元素为int的堆Q,默认建立的为大顶堆,即从堆顶取得的元素为堆中最大的元素。而在求哈夫曼树时,我们需要求得堆中最小的元素,因此使用下列语句:
priority_queue<int,vector<int>,greater<int>> Q
关于堆的有关操作如下:
Q.push()
将元素插入到堆中,自动排序
Q.pop()
弹出堆顶元素
int key=Q.top()
得到堆顶元素的值
在使用priority_queue之前的预处理:
#include<queue>
using namespace std;
代码:
#include <iostream>
#include <queue>
using namespace std;
int main()
{
priority_queue<int,vector<int>,greater<int>> Q;
int n;
while (scanf("%d",&n)!=EOF) {
int x;
for (int i=0; i<n; i++) {
scanf("%d",&x);
Q.push(x);
}
int result=0;
while (Q.size()>1) {
int a=Q.top();
Q.pop();
int b=Q.top();
Q.pop();
result+=a+b;
Q.push(a+b);
}
printf("%d\n",result);
}
return 0;
}