c++ 优先队列 priority_queue
转自csdn的文章,仅作为学习笔记。原文链接
priority_queue
介绍:C++ Reference
Priority queues are a type of container adaptors, specifically designed such that its first element is always the greatest of the elements it contains, according to some strict weak ordering criterion.
This context is similar to a heap, where elements can be inserted at any moment, and only the max heap element can be retrieved (the one at the top in the priority queue).
Priority queues are implemented as container adaptors, which are classes that use an encapsulated object of a specific container class as its underlying container, providing a specific set of member functions to access its elements. Elements are popped from the "back" of the specific container, which is known as the top of the priority queue.
The underlying container may be any of the standard container class templates or some other specifically designed container class. The container shall be accessible through random access iterators and support the following operations:
-
- empty()
- size()
- front()
- push_back()
- pop_back()
The standard container classes vector and deque fulfill these requirements. By default, if no container class is specified for a particular priority_queue class instantiation, the standard container vector is used.
Support of random access iterators is required to keep a heap structure internally at all times. This is done automatically by the container adaptor by automatically calling the algorithm functions make_heap, push_heap and pop_heap when needed.
人话就是:优先级队列是一种容器适配器,经过专门设计,以使其按照某些严格的弱排序标准。priority_queue 和 queue 不同的就在于我们可以自定义其中数据的优先级,让优先级高的排在队列前面,优先出队。优先队列具有队列的所有特性,包括基本操作,只是在这基础上添加了内部的一个排序,它本质是一个堆实现的。
和队列基本操作相同:
-
- top 访问队头元素
- empty 队列是否为空
- size 返回队列内元素个数
- push 插入元素到队尾 (并排序)
- emplace 原地构造一个元素并插入队列
- pop 弹出队头元素
- swap 交换内容
定义
头文件 #include <queue>
template <class T, class Container = vector<T>, class Compare = less<typename Container::value_type> > class priority_queue;
priority_queue<Type, Container, Functional>
Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式,当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大根堆
一般是:
//降序队列,大根堆 priority_queue <int,vector<int>,less<int> >q; //升序队列,小根堆 priority_queue <int,vector<int>,greater<int> > q; //greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了)
实现
基本类型例子
#include<iostream> #include <queue> using namespace std; int main() { //对于基础类型 默认是大顶堆 priority_queue<int> a; //等同于 priority_queue<int, vector<int>, less<int> > a; // 这里一定要有空格,不然成了右移运算符↓ priority_queue<int, vector<int>, greater<int> > c; //这样就是小顶堆 priority_queue<string> b; for (int i = 0; i < 5; i++) { a.push(i); c.push(i); } while (!a.empty()) { cout << a.top() << ' '; a.pop(); } cout << endl; while (!c.empty()) { cout << c.top() << ' '; c.pop(); } cout << endl; b.push("abc"); b.push("abcd"); b.push("cbd"); while (!b.empty()) { cout << b.top() << ' '; b.pop(); } cout << endl; return 0; }
输出
4 3 2 1 0 0 1 2 3 4 cbd abcd abc
pari的比较,先比较第一个元素,第一个相等比较第二个
#include <iostream> #include <queue> #include <vector> using namespace std; int main() { priority_queue<pair<int, int> > a; pair<int, int> b(1, 2); pair<int, int> c(1, 3); pair<int, int> d(2, 5); a.push(d); a.push(c); a.push(b); while (!a.empty()) { cout << a.top().first << ' ' << a.top().second << '\n'; a.pop(); } }
输出
2 5 1 3 1 2
对于自定义类型
#include <iostream> #include <queue> using namespace std; //方法1 struct tmp1 //运算符重载< { int x; tmp1(int a) {x = a;} bool operator<(const tmp1& a) const { return x < a.x; //大顶堆 } }; //方法2 struct tmp2 //重写仿函数 { bool operator() (tmp1 a, tmp1 b) { return a.x < b.x; //大顶堆 } }; int main() { tmp1 a(1); tmp1 b(2); tmp1 c(3); priority_queue<tmp1> d; d.push(b); d.push(c); d.push(a); while (!d.empty()) { cout << d.top().x << '\n'; d.pop(); } cout << endl; priority_queue<tmp1, vector<tmp1>, tmp2> f; f.push(c); f.push(b); f.push(a); while (!f.empty()) { cout << f.top().x << '\n'; f.pop(); } }
输出
3 2 1 3 2 1
实例
前 K 个高频元素
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
分析:
小根堆
- 遍历数组,哈希表录入频率
- 遍历哈希表,维护一个出现频率前k多的小根堆
- 优先队列已满,需要判断当前元素的频率是否大于优先队列的最小频率元素的频率,如果大于,则替换。
- 优先队列未满,进队即可
注意:c++ 优先队列默认大根堆,设置时需要priority_queue< pair<int,int> , vector< pair<int,int> >, greater< pair<int,int> > >实现小根堆。
class Solution { public: vector<int> topKFrequent(vector<int>& nums, int k) { unordered_map<int,int> record; //(元素,频率) //遍历数组,录入频率 for(int i = 0; i < nums.size(); i++){ record[nums[i]]++; } int n = record.size(); //扫描record。维护当前出现频率最多的k个元素 //最小堆。如果当前元素的频率大于优先队列中最小频率元素的频率,则替换 //优先队列中,按频率排序,所以数据对是(频率,元素)形式 priority_queue< pair<int,int> , vector< pair<int,int> >, greater< pair<int,int> > > pq; for(auto iter = record.begin(); iter != record.end(); iter++){ if(k == pq.size()){ //队列已满 if(iter->second > pq.top().first){ pq.pop(); pq.push(make_pair(iter->second,iter->first)); } } else{ pq.push(make_pair(iter->second,iter->first)); } } vector<int> result; while(!pq.empty()){ result.push_back(pq.top().second); pq.pop(); } //更正 reverse(result.begin(), result.end()); return result; } };