转自:https://blog.csdn.net/weixin_36888577/article/details/79937886
2.函数原型
priority_queue<Type, Container, Functional>
Type 就是数据类型,Container 就是容器类型(默认使用的是vector),Functional 就是比较的方式,默认是大顶堆。
//降序队列(默认)
priority_queue <int,vector<int>,less<int> >q;
//升序队列 priority_queue <int,vector<int>,greater<int> > q;//这里没有空格也是对的
2.1为什么less是大顶堆?
https://blog.csdn.net/caozicheng1999/article/details/109907795
greater和less都是结构体,分别都重载了()运算符:
// TEMPLATE STRUCT greater template<class _Ty> struct greater : public binary_function<_Ty, _Ty, bool> { // functor for operator> bool operator()(const _Ty& _Left, const _Ty& _Right) const { // apply operator> to operands return (_Left > _Right);//是大于 } }; // TEMPLATE STRUCT less template<class _Ty> struct less : public binary_function<_Ty, _Ty, bool> { // functor for operator< bool operator()(const _Ty& _Left, const _Ty& _Right) const { // apply operator< to operands return (_Left < _Right);//是小于 } };
在sort中,默认的是less<>(),从小到大排序;greater<>()是从大到小排序。
在优先级队列中,当使用默认的定义时,即less<>(),当向堆中插入一个元素时,直接插入在了尾部,然后向上调整:
void push(const value_type& _Val) { c.push_back(_Val); _STD push_heap(c.begin(), c.end(), comp); }
通过_Push_heap_by_index
template <class _RanIt, class _Ty, class _Pr> _CONSTEXPR20 void _Push_heap_by_index( _RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t<_RanIt> _Top, _Ty&& _Val, _Pr _Pred) { // percolate _Hole to _Top or where _Val belongs, using _Pred using _Diff = _Iter_diff_t<_RanIt>; for (_Diff _Idx = (_Hole - 1) >> 1; // shift for codegen //这里定义的_Idx应该就是父节点的下标 _Top < _Hole && _DEBUG_LT_PRED(_Pred, *(_First + _Idx), _Val); //当 _Idx = (_Hole - 1) >> 1) { // shift for codegen // move _Hole up to parent *(_First + _Hole) = _STD move(*(_First + _Idx)); _Hole = _Idx; } *(_First + _Hole) = _STD move(_Val); // drop _Val into final hole }
关键是这一句, _DEBUG_LT_PRED(_Pred, *(_First + _Idx), _Val),传入的仿函数用在了这里,当 *(_First + _Idx) < _Val 时返回 true ,即当父节点的值小于新插入的值时继续调整,less函数返回true,父节点被插入结点换了下去,所以我们才可以得出结论 less函数,返回true时,左边的优先级低于右边的优先级,也就清楚了为什么默认传入less反而形成的是大根堆。
优先级队列中less也就是<定义的是优先级,针对a<b返回true,表示值小的那么优先级也低,因为b更大,所以b的优先级高,优先级队列是按照优先级排序的;
针对greater,也就是重定义了>,a>b时返回true,值小的优先级反而高,所以是小顶堆。
//确实挺难理解的。
3.例子
3.1普通用法
#include <iostream> #include<vector> #include<queue> using namespace std; int main(){ priority_queue<int> a; priority_queue<int, vector<int>, greater<int>> b; for(int i=0;i<5;i++) b.push(i); while(!b.empty()){ cout<<b.top()<<" "; b.pop(); } } #输出: 0 1 2 3 4
注意,优先队列不能用for循环访问:
for(auto bb:b) cout<<bb<<" "; //报错: 'const class std::priority_queue<int,std::vector<int, std::allocator<int> >, std::greater<int> >' has no member named 'end'
就像队列不能通过for循环访问一样。
3.2 pair比较
#include <iostream> #include<vector> #include<queue> using namespace std; int main(){ priority_queue<pair<int,int>> pq; pq.push(make_pair(3,5));//make_pair()是函数。 pq.push(make_pair(4,6)); pq.push(make_pair(1,7)); while(!pq.empty()){ cout<<pq.top().first<<" "<<pq.top().second<<endl; pq.pop(); } return 0; }
输出:
4 6 3 5 1 7
默认是大顶堆,默认的话就是less?但是是如何实现排序的呢?从小到大?然后每次top都是最后一个元素出来?
3.3 自定义类型
例子347. 前 K 个高频元素,需要定义一个小顶堆,
static bool cmp(pair<int,int> a,pair<int,int> b){ return a.second>b.second; //这里是>号 } priority_queue<pair<int,int>,vector<pair<int,int>>,decltype(&cmp)> pq(cmp);
其中priority_queue的模板有三个参数:
- 第一个是元素类型
- 第二个是容器类型
- 第三个是Compare,是size_type类型的,无符号整型。
priority_queue的构造函数的参数中有comp,表示用于排序堆的比较对象。默认是less<T>大顶堆。如果是自定义的比较函数,那么需要向如上声明。
当要自定义比较函数时,大于小于号的确定:
template<class T> struct greater: public binary function<T, T, bool> { bool operator()(const T& x, const T& y) const { return x > y; } };
上面是greater类的模板,用它定义的优先队列是小顶堆。
(即大于号定义小顶堆,默认是大顶堆,小于号定义大顶堆。)