浅谈C++ STL中的优先队列(priority_queue)
从我以前的博文能看出来,我是一个队列爱好者,很多并不是一定需要用队列实现的算法我也会采用队列实现,主要是由于队列和人的直觉思维的一致性导致的。
今天讲一讲优先队列(priority_queue),实际上,它的本质就是一个heap,我从STL中扒出了它的实现代码,大家可以参考一下。
首先函数在头文件<queue>中,归属于命名空间std,使用的时候需要注意。
队列有两种常用的声明方式:
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,默认情况下,会选择第一个参数决定的类的<运算符来做这个比较函数。
接下来开始坑爹了,虽然用的是less结构,然而,队列的出队顺序却是greater的先出!就是说,这里这个参数其实很傲娇,表示的意思是如果!cmp,则先出列,不管这样实现的目的是啥,大家只能接受这个实现。实际上,这里的第三个参数可以更换成greater,像下面这样:
std::priority_queue<T, std::vector<T>, greater<T>> pq;
一般大家如果是自定义类就干脆重载<号时注意下方向了,没人在这里麻烦,这个选择基本上是在使用int类还想小值先出列时。
从上面的剖析我们也就知道了,想要让自定义类能够使用优先队列,我们要重载小于号。
class Student
{
int id;
char name[];
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<int, std::vector<int>, cmp> pq;
pq.push(s);
d[s] = ;
while (!pq.empty())
{
int tmp = pq.top();pq.pop();
for (int i = ;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();
}
浅谈C++ STL中的优先队列(priority_queue)的更多相关文章
- 浅谈C++ STL string容器
浅谈C++ STL string容器 本篇随笔简单讲解一下\(C++STL\)中\(string\)容器的使用方法及技巧. string容器的概念 其实\(string\)并不是\(STL\)的一种容 ...
- 浅谈C++ STL list 容器
浅谈C++ STL list 容器 本篇随笔简单讲解一下\(C++STL\)中\(list\)容器的使用方法和使用技巧. list容器的概念 学习过\(C++STL\)的很多同学都知道,\(STL\) ...
- 浅谈C++ STL vector 容器
浅谈C++ STL vector 容器 本篇随笔简单介绍一下\(C++STL\)中\(vector\)容器的使用方法和常见的使用技巧.\(vector\)容器是\(C++STL\)的一种比较基本的容器 ...
- 浅谈C++ STL queue 容器
浅谈C++ STL queue 容器 本篇随笔简单介绍一下\(C++STL\)中\(queue\)容器的使用方法和常见的使用技巧.\(queue\)容器是\(C++STL\)的一种比较基本的容器.我们 ...
- 浅谈C++ STL stack 容器
浅谈C++ STL stack 容器 本篇随笔简单介绍一下\(C++STL\)中\(stack\)容器的使用方法和常见的使用技巧. stack容器的概念 \(stack\)在英文中是栈的意思.栈是一种 ...
- 浅谈C++ STL deque 容器
浅谈C++ STL deque 容器 本篇随笔简单介绍一下\(C++STL\)中\(deque\)容器的使用方法及常见使用技巧. deque容器的概念 \(deque\)的意义是:双端队列.队列是我们 ...
- 转: 浅谈C/C++中的指针和数组(二)
转自:http://www.cnblogs.com/dolphin0520/archive/2011/11/09/2242419.html 浅谈C/C++中的指针和数组(二) 前面已经讨论了指针和数组 ...
- 转:浅谈C/C++中的指针和数组(一)
再次读的时候实践了一下代码,结果和原文不一致 error C2372: 'p' : redefinition; different types of indirection 不同类型的间接寻址 /// ...
- 转载 浅谈C/C++中的static和extern关键字
浅谈C/C++中的static和extern关键字 2011-04-21 16:57 海子 博客园 字号:T | T static是C++中常用的修饰符,它被用来控制变量的存贮方式和可见性.ext ...
随机推荐
- ant的设置properties
特点 大小写敏感: 不可改变,先到先得,谁先设定,之后的都不能改变. 怎样设置 1 .设置 name 和 value 属性值,比如: <property name="srcdir&qu ...
- unity使用UGUI创建摇杆
1.现在unity做一个项目,各种插件各种包,于是项目资源就无限变大了,其实一些简单的功能可以自己写,这里就是试着使用UGUI编写一个摇杆功能 2.脚本如下: using UnityEngine; u ...
- 【Qt编程】Qt学习之窗口间的相互切换
在用Qt设计GUI时,经常要设计两个窗口之间的相互切换,即可以从一个窗口跳转到另一个窗口,然后又从另一个窗口跳转回原窗口.下面我们来介绍具体的实现方法: 工程建立及功能描述: 首先,我们建立Qt G ...
- gcc学习(二)[第二版]
头文件与库文件 1.概要 在使用C语言和其他语言进行程序设计的时候,我们需要头文件来提供对常数的定义和对系统及库函数调用的声明. 库文件是一些预先编译好的函数集合,那些函数都是按照可重用原则编写的.它 ...
- 粒子系统属性Life,发射速率和总数的关系
提示,粒子系统的life,发射速率以及总粒子数是相互影响的. 如果你要发射器射出粒子流然后停顿一会,你将简单的必须确保lifetime和发射速率相匹配以至于在发射出的粒子达到粒子总数之前一些粒子是活跃 ...
- BASE64Decoder小解
BASE64Decoder小解 Base64 是网络上最常见的用于传输8Bit 字节代码的编码方式之一,大家可以查看RFC2045 -RFC2049 ,上面有MIME 的详细规范. Base64 要求 ...
- 重新初始化VS2010
开始->所有程序->Microsoft Visual Studio 2010->Visual Studio Tools->Visual Stdio命令提示(2010) 这时会 ...
- 数据挖掘进阶之序列模式挖掘GSP算法
数据挖掘进阶之序列模式挖掘GSP算法 绪 继续数据挖掘方面算法的讲解,前面讲解了数据挖掘中关联规则算法FP-Growth的实现.此篇博文主要讲解基于有趣性度量标准的GSP序列模式挖掘算法.有关论文后期 ...
- Leetcode_190_Reverse Bits
), return 964176192 (represented in binary as00111001011110000010100101000000). 思路: (1)题意为给定无符号32位整数 ...
- Detours修改段属性漏洞
v:* { } o:* { } w:* { } .shape { }p.MsoNormal,li.MsoNormal,div.MsoNormal { margin: 0cm; margin-botto ...