8. 哈夫曼树的应用
题目来源和说明
2010年北京邮电大学计算机研究生机试真题,我们以这个题为例梳理和总结哈夫曼树的应用。
题目描述
哈夫曼树,第一行输入一个数n,表示叶结点的个数。需要用这些叶结点生成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即weight,题目需要输出所有结点的值与权值的乘积之和的最小值。
样例
输入:
5
1 2 2 5 9
复制
输出:
37
简要分析
我们每次都从集合K总选出两个权值最小的节点,这不妨让我们想到了最小堆的性质。于是我们可以直接使用stl的最小堆实现的优先级队列,每次pop出两个最小的,然后加起来形成的新节点再push进去就行,这样时间复杂度也变小O(logn)
注意
priority_queue<int> Q;//这样建立的堆默认为最大堆,因此不适合哈夫曼树
priority_queue<int,vector<int>,greater<int>> Q;这样定义的是一个最小堆
C++ 代码
#include<iostream>
#include<queue>
using namespace std;
priority_queue<int,vector<int>,greater<int>> Q; //建立一个小顶堆
int main() {
int n;
while(scanf("%d",&n)!=EOF) {
while(Q.empty()==false) Q.pop(); //清空
for(int i=1;i<=n;i++) {
int x;
scanf("%d",&x);
Q.push(x); //吧权值放入堆中,会自动维护小顶堆的性质
}
int ans=0;
while(Q.size()>1) {
int a=Q.top();//取堆顶,即最小的
Q.pop(); //探出
int b=Q.top();//取堆顶,即最小的
Q.pop();
ans+=a+b;
Q.push(a+b);
}
printf("%d\n",ans);
}
return 0;
}
同类题目
- 搬水果
https://www.nowcoder.com/questionTerminal/e4c775b0f3ee42a4bb72c26d2e1eef8a
简要分析
拿到这道题目,首先想到的是贪心的思想,我总是选择两堆重量最小的,这样是局部最优解。那这就回到了我们的例题。从一个集合K总选择两个最小的,并将其和返回集合K总,这就是哈夫曼树的概念。具体的代码如下:
C++代码
#include<iostream>
#include<queue>
using namespace std;
priority_queue<int,vector<int>,greater<int>> Q;
int main() {
int n;
while(scanf("%d",&n)!=EOF&&n!=0) {
while(!Q.empty()) Q.pop(); //清空
for(int i=0;i<n;i++) {
int x;scanf("%d",&x);
Q.push(x);
}
int ans=0;
while(Q.size()>1) {
int a=Q.top();Q.pop();
int b=Q.top();Q.pop();
ans+=a+b;
Q.push(a+b);
}
printf("%d\n",ans);
}
return 0;
}
高校夏令营机试训练 文章被收录于专栏
Leetcode题目太多,不知道如何准备高校夏令营?欢迎关注本专栏,和本小白一起准备夏令营吧! 本专题的规划如下: 截止到4月下旬:以王道考研为依托,提供夏令营机考的准备计划,打好基础 截止到5月中旬:以剑指offer进一步加强 本专题的内容如下: 1. 给出题目的在线测试链接,方面您检查代码的正确性 2. 给出题解