博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅谈C++ STL中的优先队列(priority_queue)
阅读量:7213 次
发布时间:2019-06-29

本文共 2947 字,大约阅读时间需要 9 分钟。

hot3.png

从我以前的博文能看出来,我是一个队列爱好者,很多并不是一定需要用队列实现的算法我也会采用队列实现,主要是由于队列和人的直觉思维的一致性导致的。

今天讲一讲优先队列(priority_queue),实际上,它的本质就是一个heap,我从STL中扒出了它的实现代码,大家可以参考一下。

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

队列有两种常用的声明方式:

std::priority_queue
pq;std::priority_queue
, cmp> pq;

 

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

template
, class _Pr = less
> class priority_queue

 

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

接下来开始坑爹了,虽然用的是less结构,然而,队列的出队顺序却是greater的先出!就是说,这里这个参数其实很傲娇,表示的意思是如果!cmp,则先出列,不管这样实现的目的是啥,大家只能接受这个实现。实际上,这里的第三个参数可以更换成greater,像下面这样:

std::priority_queue
, greater
> pq;

 

一般大家如果是自定义类就干脆重载<号时注意下方向了,没人在这里麻烦,这个选择基本上是在使用int类还想小值先出列时。

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

复制代码

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

复制代码

 

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

如果我们不使用自定义类,又要用非默认方法去排序怎么办?就比如说在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
, 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
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

转载于:https://my.oschina.net/u/4000302/blog/3020098

你可能感兴趣的文章
MySQL的编译安装
查看>>
使用SSH连接CentOS步骤
查看>>
Elasticsearch 5 Ik+pinyin分词配置详解
查看>>
jsp实现简单的分页
查看>>
阿里云虚拟主机数据库主机怎么看
查看>>
[投稿]通过Web界面在多台服务器上批量创建文件
查看>>
Oracle 性能相关常用脚本(SQL)
查看>>
commit your changes or stash them before you can merge
查看>>
Linux Shell执行原理
查看>>
DATA GUARD架构(一)
查看>>
MapReduce1和Yarn的工作机制
查看>>
awk 以列为域提取文件内容
查看>>
NEC中标里斯本智慧城市项目 助力城市整体数字化变革
查看>>
[转] 大规模服务设计部署经验谈
查看>>
Debian手动修改ip地址
查看>>
Realm的简单使用
查看>>
zabbix使用zabbix 数据库做数据分表
查看>>
Oracle 11g dataguard三种模式以及实时查询(Real-time query)功能设置
查看>>
exchange 2013 lesson 6 CAS HA installing
查看>>
Groovy中的闭包
查看>>