作为一个实用主义,此篇暂时不介绍堆的具体结构,只快速地帮助读者了解如何使用。
p r i o r i t y _ q u e u e priority\_queue priority_queue:优先队列,是一种堆。
大根堆:
p r i o r i t y _ q u e u e < i n t , v e c t o r < i n t > , l e s s < i n t > > q priority\_queue<int,vector<int>,less<int>>\ q priority_queue<int,vector<int>,less<int>> q
或者直接写成:
p r i o r i t y _ q u e u e < i n t > q priority\_queue<int> \ q priority_queue<int> q
因为优先队列默认为大根堆。对他操作时一般只在堆顶操作,因为堆顶有一个特性就是:堆顶始终是堆中最大的元素,也就是 q . t o p ( ) q.top() q.top()是堆中最大的元素。
小根堆写法:
p r i o r i t y _ q u e u e < i n t , v e c t o r < i n t > , g r e a t e r < i n t > > q priority\_queue <int, vector<int>, greater<int>>\ q priority_queue<int,vector<int>,greater<int>> q
与大根堆一样,只不过堆顶变成了堆中最小的元素。
对堆的操作:
- q . s i z e ( ) q.size() q.size():返回堆中元素的个数。
- q . e m p t y ( ) q.empty() q.empty(): 判断堆中是否为空,空则返回1,否则返回0。
- q . p o p ( ) q.pop() q.pop():弹出堆顶元素。
- q . t o p ( ) q.top() q.top():返回堆顶元素。
- q . p u s h ( ) q.push() q.push():往堆中添加元素。
总结下来,堆的用途就是可以很好的维护一些元素中的最小值或最大值。
结合题目理解一下:
题目描述
你有一个菜篮子。
接下来 Q Q Q次操作,每次操作如下:
- “1 x”,将一个重量为 x x x的菜放入到菜篮子中。
- “2”,将菜篮子中重量最大的菜丢掉(如果菜篮子为空,则跳过)。
问 Q Q Q次操作后,菜篮子中剩下的菜的总重量。
输入描述
第一行一个整数 Q Q Q,表示操作次数。 ( 1 ≤ Q ≤ 1 0 5 ) (1≤Q≤10^5) (1≤Q≤105)
接下来 Q Q Q行,每行一条操作。 ( 1 ≤ x ≤ 1 0 9 ) (1≤x≤10^9) (1≤x≤109)
输出描述
一个整数表示答案
利用优先队列,当输入操作 1 1 1时把 x x x丢进优先队列里,并将x加进答案。当输入操作 2 2 2时,在答案里减去 x x x,再将堆顶弹出即可。
#include<bits/stdc++.h>
using ll = long long;
using namespace std;
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
priority_queue<ll> pq;
ll sum = 0;
int q; cin >> q;
while(q--)
{
int op; cin >> op;
if(op == 1)
{
ll x; cin >> x;
pq.push(x);
sum += x;
}
if(op == 2 && pq.size())
{
sum -= pq.top();
pq.pop();
}
}
cout << sum << '\n';
return 0;
}
实际应用:动态维护数组内的最大值或最小值。
更详细内容可以看看starrycoding中的算法基础课,联系笔者可以争取半价(真妹卖课,只是这课真的很好,推荐给大家)。
后续内容持续更新中~