一、priority_queue的使用
template <class T, class Container = vector<T>,class Compare = less<typename Container::value_type> >
class priority_queue;
优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆的算法将vector的元素构成了堆的结构,所有需要用到堆的位置,都可以考虑使用priority_queue。注意默认情况下priority_queue使用
大堆。
有关堆结构,可以参考我的另外一篇博客有详细说明了对堆的分析,包括建堆,堆排序,堆向上、向下调整:图解二叉堆:堆排序
1.1、priority_queue的常用接口
函数声明 | 接口说明 |
---|---|
priority_queue()/priority_queue(first,last) | 构造一个空的优先级队列 |
empty() | 检测优先级队列是否为空 |
top() | 返回优先级队列中优先级堆高的元素,堆顶元素 |
push(x) | 在优先级队列中插入元素x |
pop() | 删除优先级队列中堆顶的元素 |
1.2、默认情况下priority_queue是大堆
#include <vector>
#include <queue> //priority_queue 的头文件
#include <functional> // greater算法的头文件
int main() {
// 默认情况下,创建的是大堆,其底层按照小于号比较
vector<int> v{ 3,2,7,6,0,4,1,9,8,5 };
priority_queue<int> q1;
for (auto& e : v)
q1.push(e);
cout << "默认less比较方式大根堆输出:" << endl;
while (!q1.empty()) {
cout << q1.top() << " ";
q1.pop();
}
cout << endl;
// 如果要创建小堆,将第三个模板参数换成greater比较方式,所以要给出完整的定义
priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());
cout << "修改为greater比较方式小根堆输出:" << endl;
while (!q2.empty()) {
cout << q2.top() << " ";
q2.pop();
}
}
1.3、如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中重载>或<运算符
- 如果要建大堆,需要用户在自定义类型中提供< 的重载。
- 如果要建小堆,需要用户在自定义类型中提供> 的重载。
#include <vector>
#include <queue> //priority_queue 的头文件
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
: _year(year)
, _month(month)
, _day(day)
{}
bool operator<(const Date& d)const
{
return (_year < d._year) ||
(_year == d._year && _month < d._month) ||
(_year == d._year && _month == d._month && _day < d._day);
}
bool operator>(const Date& d)const
{
return (_year > d._year) ||
(_year == d._year && _month > d._month) ||
(_year == d._year && _month == d._month && _day > d._day);
}
friend ostream& operator<<(ostream& _cout, const Date& d)
{
_cout << d._year << "-" << d._month << "-" << d._day;
return _cout;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
// 大堆,需要用户在自定义类型中提供<的重载
priority_queue<Date> q1;
q1.push(Date(2018, 10, 29));
q1.push(Date(2018, 10, 28));
q1.push(Date(2018, 10, 30));
cout << q1.top() << endl;
// 如果要创建小堆,需要用户提供>的重载
priority_queue<Date, vector<Date>, greater<Date>> q2;
q2.push(Date(2018, 10, 29));
q2.push(Date(2018, 10, 28));
q2.push(Date(2018, 10, 30));
cout << q2.top() << endl;
}
1.4、在OJ中的使用
class Solution {
public:
//使用仿函数,创建小堆,提供 > 的重载
struct cmp{
bool operator()(const pair<int,int>& lt,const pair<int,int>&rt){
return lt.second>rt.second;
}
};
vector<int> topKFrequent(vector<int>& nums, int k) {
vector<int> res;
unordered_map<int,int> hash;
for(int i=0;i<nums.size();++i) ++hash[nums[i]];
priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> pq;
for(auto it=hash.begin();it!=hash.end();++it){
pq.push(*it);
if(pq.size()>k){
pq.pop();
}
}
while(!pq.empty()){
res.push_back(pq.top().first);
pq.pop();
}
return res;
}
};
二、priority_queue的模拟实现
namespace MyPriorityQueue {
template<class T, class Container = vector<T>, class Compare = less<T> >
class priority_queue {
public:
priority_queue() = default;
template<class InputIterator>
priority_queue(InputIterator first, InputIterator last)
:_con(first, last)
{
//从下往上建堆
for (size_t i = (_con.size() - 1 - 1) / 2; i >= 0; i--) {
AdjustDown(i);
}
从上往下建堆
//for (size_t i = 1; i < _con.size(); i++) {
// AdjustUp(i);
//}
}
void push(const T& x) {
_con.push_back(x);
AdjustUp(_con.size() - 1);
}
void pop() {
assert(size() > 0);
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
AdjustDown(0);
}
const T& top() const {
return _con[0];
}
T& top() {
return _con[0];
}
size_t size()const {
return _con.size();
}
bool empty() const {
return _con.empty();
}
private:
void AdjustDown(size_t parent) {
size_t child = parent * 2 + 1;
while (child < _con.size()) {
if (child + 1 < _con.size() && cmp(_con[child],_con[child + 1])) {
child++;
}
if (cmp(_con[parent],_con[child])) {
swap(_con[child], _con[parent]);
parent = child;
child = parent * 2 + 1;
}
else {
break;
}
}
}
void AdjustUp(int child) {
int parent = (child - 1) / 2;
while (child > 0) {
if (cmp(_con[parent],_con[child])) {
swap(_con[child], _con[parent]);
child = parent;
parent = (child - 1) / 2;
}
else {
break;
}
}
}
private:
Container _con;
Compare cmp;
};
}