浅谈C++ STL中的优先队列(priority_queue)

从我之前的博文能看出来,我是一个队列爱好者,不少并非必定须要用队列实现的算法我也会采用队列实现,主要是因为队列和人的直觉思惟的一致性致使的。html

今天讲一讲优先队列(priority_queue),实际上,它的本质就是一个heap,我从STL中扒出了它的实现代码,你们能够参考一下。算法

首先函数在头文件<queue>中,归属于命名空间std,使用的时候须要注意。less

队列有两种经常使用的声明方式:函数

std::priority_queue<T> pq;
std::priority_queue<T, std::vector<T>, cmp> pq;

 

第一种实现方式较为经常使用,接下来我给出STL中的对应声明,再加以解释。性能

template<class _Ty,
    class _Container = vector<_Ty>,
    class _Pr = less<typename _Container::value_type> >
    class priority_queue

 

你们能够看到,默认模板有三个参数,第一个是优先队列处理的类,第二个参数比较有特色,是容纳优先队列的容器。实际上,优先队列是由这个容器+C语言中关于heap的相关操做实现的。这个容器默认是vector,也能够是dequeue,由于后者功能更强大,而性能相对于vector较差,考虑到包装在优先队列后,后者功能并不能很好发挥,因此通常选择vector来作这个容器。第三个参数比较重要,支持一个比较结构,默认是less,默认状况下,会选择第一个参数决定的类的<运算符来作这个比较函数。htm

接下来开始坑爹了,虽然用的是less结构,然而,队列的出队顺序倒是greater的先出!就是说,这里这个参数其实很傲娇,表示的意思是若是!cmp,则先出列,无论这样实现的目的是啥,你们只能接受这个实现。实际上,这里的第三个参数能够更换成greater,像下面这样:blog

std::priority_queue<T, std::vector<T>, greater<T>> pq;

 

通常你们若是是自定义类就干脆重载<号时注意下方向了,没人在这里麻烦,这个选择基本上是在使用int类还想小值先出列时。排序

从上面的剖析咱们也就知道了,想要让自定义类可以使用优先队列,咱们要重载小于号。队列

复制代码

class Student
{
    int id;
    char name[20];
    bool gender;
    bool operator < (Student &a) const
    {
        return id > a.id;
    }
};

复制代码

 

就拿这个例子说,咱们想让id小的先出列,怎么办,就要很违和的给这个小于符号重载成其实是大于的定义。ci

若是咱们不使用自定义类,又要用非默认方法去排序怎么办?就好比说在Dijkstra中,咱们固然不会用点的序号去排列,不管是正序仍是反序,咱们想用点到起点的距离这个值来进行排序,咱们怎样作呢?细心的读者在阅读个人有关Dijkstra那篇文章时应该就发现了作法——自定义比较结构。优先队列默认使用的是小于结构,而上文的作法是为咱们的自定义类去定义新的小于结构来符合优先队列,咱们固然也能够自定义比较结构。自定义方法以及使用以下,我直接用Dijkstra那篇的代码来讲明:

复制代码

int cost[MAX_V][MAX_V];
int d[MAX_V], V, s;
//自定义优先队列less比较函数
struct cmp
{
    bool operator()(int &a, int &b) const
    {
        //由于优先出列断定为!cmp,因此反向定义实现最小值优先
        return d[a] > d[b];
    }
};
void Dijkstra()
{
    std::priority_queue<int, std::vector<int>, cmp> pq;
    pq.push(s);
    d[s] = 0;
    while (!pq.empty())
    {
        int tmp = pq.top();pq.pop();
        for (int i = 0;i < V;++i)
        {
            if (d[i] > d[tmp] + cost[tmp][i])
            {
                d[i] = d[tmp] + cost[tmp][i];
                pq.push(i);
            }
        }
    }
}

复制代码

 

优先队列的平常使用,了解上面那些就已经足够。下面给出优先队列的全部成员函数的STL实现方法,但愿你看完没有一脸卧槽的感受。c就是你声明时候的那个vector或者其余容器。

复制代码

void push(value_type&& _Val)
        {    // insert element at beginning
        c.push_back(_STD move(_Val));
        push_heap(c.begin(), c.end(), comp);
        }

    template<class... _Valty>
        void emplace(_Valty&&... _Val)
        {    // insert element at beginning
        c.emplace_back(_STD forward<_Valty>(_Val)...);
        push_heap(c.begin(), c.end(), comp);
        }


    bool empty() const
        {    // test if queue is empty
        return (c.empty());
        }

    size_type size() const
        {    // return length of queue
        return (c.size());
        }

    const_reference top() const
        {    // return highest-priority element
        return (c.front());
        }

    void push(const value_type& _Val)
        {    // insert value in priority order
        c.push_back(_Val);
        push_heap(c.begin(), c.end(), comp);
        }

    void pop()
        {    // erase highest-priority element
        pop_heap(c.begin(), c.end(), comp);
        c.pop_back();
        }

复制代码

https://www.cnblogs.com/cielosun/p/5654595.html

相关文章
相关标签/搜索