priority_queue学习

转自: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类的模板,用它定义的优先队列是小顶堆。

(即大于号定义小顶堆,默认是大顶堆,小于号定义大顶堆。)

原文地址:https://www.cnblogs.com/BlueBlueSea/p/13870441.html