参考连接
值得关注的知识点:
C++中提供优先队列的模板供使用,优先队列的底层实现就是堆,priority_queue包含在头文件#include
中。
优先队列priority_queue也是一个队列,含有队列的一切特征,例如先进先出、只能从队头出,队尾入。优先队列在普通队列的基础上增加了内部的一个排序,这个排序本质是由堆实现的。
template <typename T, typename Container=std::vector<T>, typename Compare=std::less<T>> class priority_queue
可以看出,priority_queue模板有三个参数:
vector
less
函数对应获得一个大顶堆,greater
对应获得一个小顶堆。//默认是一个使用vec作为底层容器的大顶堆
priority_queue<string>words;
string words[]{"one", "two", "three"};
priority_queue<string>w{words.begin(), words.end()}; //字母顺序"two", "three", "one"
注:这里跟前面堆介绍中说升序用大根堆,降序用小根堆不一样,有可能原因是C++中优先队列的实现问题。
vector<int>values{25,22,54,55};
priority_queue<int>pq{less<int>(),values}; //调用pq的构造函数,其中第一个参数为比较函数对象,第二个函数用于初始化容器元素(可缺省)
和队列基本相同:
emplace可以直接调用对象的构造函数,有区别于push的参数传入的形式,属于C++中优化的方式,具体可以参考emplace与push_back
用pair做优先级队列:先比较第一个元素,后比较第二个元素
pq.push(pair<int, int>(1, 2));
pq.push(pair<int, int>(2, 3));
pq.push(pair<int, int>(2, 4));
while (!pq.empty()) {
cout << pq.top().first << " " << pq.top().second << endl;;
pq.pop();
}
经典的topK问题:
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
//优先队列做法(实际上是堆排序)
map<int,int>mp;
for(auto &_num:nums){
mp[_num]++;
}
auto cmp = [](pair<int,int>a, pair<int, int>b){return a.second > b.second;}; //这里定义为小根堆
//定义优先队列,按小根堆排序,优先队列中每个pair的第一个元素为数字,第二个元素为出现次数
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(cmp)>pq{cmp}; //关注这里的定义与初始化
for(auto & [num,count] : mp){
if(pq.size() == k){
//大于堆顶元素,则需要把该元素插入堆中,并弹出堆顶元素(因为要维护一个元素数量为k的堆,固要弹出)
if(pq.top().second < count){
pq.pop();
pq.emplace(num, count);
}
}
else{
pq.emplace(num, count);
}
}
vector<int>output;
主要的思路是对元素频次维护一个含有k个元素的小根堆