优先级队列
- 基本使用
- 题目训练
基本使用
priority_queue
, 优先级队列, 又叫做双端队列, 头文件也是 <queue>
别看它叫做队列, 其实它是一个 堆
补充一下概念:
- 大根堆 — — 每一棵树的父节点比它的孩子都大
- 小跟堆 — — 每一棵树的父节点比它的孩子都小
👇👇👇
void test()
{// 默认构建的是一个大堆priority_queue<int> pq;pq.push(1);pq.push(5);pq.push(4);pq.push(9);pq.push(10);pq.push(6);while (!pq.empty()){cout << pq.top() << " ";pq.pop();}}int main()
{test();return 0;
}
运行结果:
10 9 6 5 4 1
注意:
不要被这里的按序输出迷惑了,
优先级队列的内部结构是堆, 堆的内部结构是不一定按照元素的顺序排列的。
- 那如果我们要
小跟堆输出
呢?
void test()
{// 仿函数控制, greater是构建小跟堆priority_queue<int,vector<int>, greater<int> > pq;pq.push(1);pq.push(6);pq.push(20);pq.push(15);pq.push(8);pq.push(2);pq.push(6);pq.push(4);pq.push(9);pq.push(10);while (!pq.empty()){cout << pq.top() << " ";pq.pop();}}int main()
{test();return 0;
}
运行结果:
1 2 4 6 6 8 9 10 15 20
- 要构建小跟堆, 我们要用
greater
- 由于仿函数是最后一个参数, 那么处于中间位置的
容器适配器
也要给个参数
如何使用
- 使用迭代区间初始化
void test()
{vector<int> vec;vec.push_back(1);vec.push_back(2);vec.push_back(9);vec.push_back(8);vec.push_back(7);priority_queue<int> pq(vec.begin(), vec.end());while (!pq.empty()){cout << pq.top() << " ";pq.pop();}cout << endl;}int main()
{test();return 0;
}
运行结果:
9 8 7 2 1
当然我们也可以 建小堆
void test()
{vector<int> vec;vec.push_back(1);vec.push_back(2);vec.push_back(9);vec.push_back(8);vec.push_back(7);priority_queue<int,vector<int>, greater<int> > pq(vec.begin(), vec.end());while (!pq.empty()){cout << pq.top() << " ";pq.pop();}cout << endl;}int main()
{test();return 0;
}
运行结果:
1 2 7 8 9
题目训练
- 数组中的第K个最大元素
这是我们熟悉的 TopK问题
.
那么问题来了, 要求时间复杂度是 O(n)
, 我们是建小堆还是大堆呢?
其实, 建小堆 和 建大堆都是一样的
- 建大堆
- 建大堆 — — 时间复杂度是
O(n)
- pop (k-1) 次 — — 向上调整算法, 时间复杂度是
O(logN)
- 堆顶元素就是答案
- 建大堆 — — 时间复杂度是
总体的时间复杂度是 O(n)
class Solution {
public:int findKthLargest(vector<int>& nums, int k) {// 1. 建大堆 // 建堆 -- O(n)priority_queue<int> pq(nums.begin(), nums.end());// 2. pop(k-1)次// pop, 向上调整算法 -- O(logN)while(--k){pq.pop();}return pq.top();}
};
- 建小堆
- 建一个
个数为K的小堆
— — 时间复杂度是O(K)
- 将剩余元素中的
大于堆顶元素的数据 插入堆中
— — 时间复杂度是(N-K)l ogK
1. 如果 K很大, 那么时间复杂度是O(log K)
2. 如果 K很小, 那么时间复杂度是O(N)
- 返回堆顶元素
- 建一个
总体的时间复杂度是 O(n)
class Solution {
public:int findKthLargest(vector<int>& nums, int k) {// 1. 建小堆 // 建堆 -- O(n)priority_queue<int, vector<int>, greater<int> > pq(nums.begin(), nums.begin()+k);// 2. pop// pop, 向上调整算法 -- O((N-K) logK)// push, 向上调整算法 -- O((N-K) logK)for(int i = k; i < nums.size(); i++){if(nums[i] > pq.top()){pq.pop();pq.push(nums[i]);}}return pq.top();}
};
弟子曰:此学甚好,只是簿书讼狱繁难,不得为学。
阳明曰:簿书讼狱之间,无非实学;若离了事物为学,却是着空。
译文:
弟子说:先生的学问很好,但是平时工作太忙了,没空修习。
先生说:学问不能脱离工作,在工作中修行,才是真正的学习。如果脱离了实际事务,那修行就没用了。
王阳明认为:工作就是最好的修行。
把工作中遇到的烦恼,当成磨炼自己心性的机会;
把工作中的怠惰懒散,当成改变自己态度的试炼;
把工作中的愤怒委屈,当成放大格局的磨砺。
稻盛和夫说:工作中修行,是帮助我们提升心性和培养人格的最重要、也是最有效的方法。
工作是用,修身是体 ,用成长的心态去工作,就是一个人最好的修行。