priority_queue介绍
- 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。
- 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元
素)。- 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类。
- 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭
代器访问,并支持以下操作:
- empty():检测容器是否为空
- size():返回容器中有效元素个数
- front():返回容器中第一个元素的引用
- push_back():在容器尾部插入元素
- pop_back():删除容器尾部元素
- 标准容器类
vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指
定容器类,则使用vector。- 需要支持随机访问迭代器,以便始终在内部保持堆结构,但本身作为容器适配器无法遍历。
所谓优先级队列priority_queue,实际上就是我们学过的数据结构——堆,关于堆的特性及功能可参考——堆的模拟实现一文;而priority_queue跟上文介绍的stack和queue一样,都是容器适配器,都是由其他容器封装而来,但是对底层容器提出了更进一步的要求——底层容器需要支持随机访问迭代器。
迭代器种类
- 输入迭代器
Input Iterators:
- 提供了对容器中元素的单向访问能力。
- 支持的操作包括:++(前进)、*(解引用以访问元素)、== 和 !=(比较迭代器是否相等或不等)。
- 输入迭代器只能向前移动,不能反向移动,也不能直接通过迭代器来修改元素的值(尽管可以通过解引用访问到的元素间接修改,但这通常不是迭代器的职责)。
- 典型示例:
istream_iterator(用于从输入流中读取数据)。
- 输出迭代器
Output Iterators:
- 提供了向容器中写入元素的能力。
- 支持的操作包括:++(前进)、*(解引用以写入元素)。
- 输出迭代器同样只能向前移动,且不能读取元素的值,主要用于输出操作。
- 典型示例:
ostream_iterator(用于向输出流中写入数据)。
- 前向迭代器
Forward Iterators:
- 是输入迭代器的超集,支持所有输入迭代器的操作,并且保证多次通过同一迭代器解引用得到的元素值相同(即迭代器稳定)。
- 仍然只能向前移动,但比输入迭代器更加灵活,如可以用于
accumulate等算法中。 - 典型示例:
forward_list(单向链表)的迭代器。
- 双向迭代器
Bidirectional Iterators:
- 支持前向迭代器的所有操作,并增加了- -(后退)操作,允许迭代器在容器中前后移动。
- 典型示例:
list和map(注意,map的迭代器是双向的,但只能遍历键值对,不能直接修改键)的迭代器。
- 随机访问迭代器
Random Access Iterators:
- 提供了最强大的迭代器能力,支持双向迭代器的所有操作,并且增加了元素间的算术操作,如
+n、-n、+=n、-=、<、<=、>、>=。 - 这类迭代器可以像指针一样,进行随机访问和快速遍历。
- 典型示例:
vector、deque、string的迭代器。
由于priority_queue需要随机访问迭代器,所以一般使用vector,或deque作为底层容器。
priority_queue实现
老样子,封在自己的命名空间里;由于priority_queue是容器适配器,底层也是使用了别的容器(vector或deque)所以实现方法和上篇的stack和queue是一样的,具体请参考stack和queue,而的区别就是priority_queue是堆,需要借助adjust_up和adjust_down维持堆的特性。而这两个调整方法也曾在堆模拟实现一文详细介绍过。需要请参考——堆的模拟实现。
我们这里真正需要关心的是:堆有大小堆之分,如何使用同一份代码解决这个问题呢?总不能手动去改代码中的比较逻辑吧。这里的解决办法就是本文将要介绍的——仿函数。
namespace djs
{
///仿函数
template<class T>
struct Less
{
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
template<class T>
struct Greater
{
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
template<class T,

最低0.47元/天 解锁文章
1413






