适配一个容器以提供优先级队列
std::priority_queue
定义于头文件 <queue>
template< class T, |
priority_queue 是容器适配器,它提供常数时间的(默认)最大元素查找,对数代价的插入与释出。
可用用户提供的 Compare 更改顺序,例如,用 std::greater<T> 将导致最小元素作为 top() 出现。
用 priority_queue 工作类似管理某些随机访问容器中的堆,优势是不可能突然把堆非法化。
模板形参
T | - | 存储的元素类型。若 T 与 Container::value_type 不是同一类型则行为未定义。 (C++17 起) |
Container | - | 用于存储元素的底层容器类型。容器必须满足序列容器 (SequenceContainer) 的要求,而其迭代器必须满足遗留随机访问迭代器 (LegacyRandomAccessIterator) 的要求。另外,它必须提供拥有通常语义的下列函数:
标准容器 std::vector 和 std::deque 满足这些要求。 |
Compare | - | 提供严格弱序的比较 (Compare) 类型。 |
注意 比较 (Compare) 形参的定义,使得若其第一参数在弱序中先于其第二参数则返回 true 。但因为 priority_queue 首先输出最大元素,故“先来”的元素实际上最后输出。即队列头含有按照 比较 (Compare) 所施加弱序的“最后”元素。
成员函数
构造 priority_queue
std::priority_queue<T,Container,Compare>::priority_queue
priority_queue() : priority_queue(Compare(), Container()) { } | (1) | (C++11 起) |
explicit priority_queue(const Compare& compare) | (2) | (C++11 起) |
explicit priority_queue( const Compare& compare = Compare(), | (3) | (C++11 前) |
priority_queue( const Compare& compare, const Container& cont ); | (C++11 起) | |
priority_queue( const Compare& compare, Container&& cont ); | (4) | (C++11 起) |
priority_queue( const priority_queue& other ); | (5) | |
priority_queue( priority_queue&& other ); | (6) | (C++11 起) |
template< class Alloc > | (7) | (C++11 起) |
template< class Alloc > | (8) | (C++11 起) |
template< class Alloc > priority_queue( const Compare& compare, const Container& cont, const Alloc& alloc ); | (9) | (C++11 起) |
template< class Alloc > priority_queue( const Compare& compare, Container&& cont, const Alloc& alloc ); | (10) | (C++11 起) |
template< class Alloc > | (11) | (C++11 起) |
template< class Alloc > | (12) | (C++11 起) |
template< class InputIt > priority_queue( InputIt first, InputIt last, const Compare& compare, const Container& cont ); | (13) | (C++11 起) |
template< class InputIt > priority_queue( InputIt first, InputIt last, | (14) | (C++11 起) |
从多种数据源构造容器适配器的底层容器。
1) 默认构造函数。值初始化底层容器。
2) 用 compare
的内容复制构造比较函数对象 comp
。值初始化底层容器 c
。
3) 用 cont
的内容复制构造底层容器 c
。用 compare
的内容复制构造比较函数对象 comp
。调用 std::make_heap(c.begin(), c.end(), comp) 。此亦为默认构造函数。 (C++11 前)
4) 用 std::move(cont) 移动构造底层容器 c
。以 compare
的内容复制构造比较函数对象 comp
。调用 std::make_heap(c.begin(), c.end(), comp) 。
5) 复制构造函数。以 other.c 的内容复制构造底层容器。以 other.comp 复制构造比较函数对象。 (隐式声明)
6) 移动构造函数。以 std::move(other.c) 构造底层容器。以 std::move(other.comp) 构造比较函数对象。 (隐式声明)
7-12) 仅若 std::uses_allocator<container_type, Alloc>::value == true ,即若底层容器是具分配器容器(对所有标准库容器为真),才定义下列构造函数。
7) 以 alloc
为分配器构造底层容器。等效地调用 c(alloc) 。值初始化 comp
。
8) 以 alloc
为分配器构造底层容器。等效地调用 c(alloc) 。从 compare
复制构造 comp
。
9) 用 cont
的内容,以 alloc
为分配器构造底层容器,如同用 c(cont, alloc) 。从 compare
复制构造 comp
。然后调用 std::make_heap(c.begin(), c.end(), comp) 。
10) 用 cont
的内容,以 alloc
为分配器并以移动语义构造底层容器,如同用 c(std::move(cont), alloc) 。从 compare
复制构造 comp
。然后调用 std::make_heap(c.begin(), c.end(), comp) 。
11) 用 other.c
的内容,以 alloc
为分配器构造底层容器。等效地调用 c(other.c, alloc) 。从 other.comp
复制构造 comp
。
12) 用 other
的内容,同时以 alloc
为分配器构造适配器。等效地调用 c(std::move(other.c), alloc) 。从 other.comp
移动构造 comp
。
13) 从 cont
复制构造 c
并从 compare
复制构造 comp
。然后调用 c.insert(c.end(), first, last); ,再调用 std::make_heap(c.begin(), c.end(), comp); 。
14) 从 std::move(cont)
移动构造 c
并从 std::move(compare)
移动构造 comp
。然后调用 c.insert(c.end(), first, last); ,再调用 std::make_heap(c.begin(), c.end(), comp); 。
参数
alloc | - | 用于底层容器所有内存分配的分配器 |
other | - | 用作源初始化底层容器的另一容器适配器 |
cont | - | 用作源初始化底层容器的容器 |
compare | - | 用于初始化底层比较函数对象的比较函数对象 |
first, last | - | 要初始化的元素范围 |
类型要求 | ||
- Alloc 必须满足分配器 (Allocator) 的要求。 | ||
- Container 必须满足容器 (Container) 的要求。仅若 Container 满足具分配器容器 (AllocatorAwareContainer) 的要求才定义构造函数 (5-10) | ||
- InputIt 必须满足遗留输入迭代器 (LegacyInputIterator) 的要求。 |
复杂度
1-2) 常数。
3,5) O(N) 次比较,其中 N 为 cont.size() 。
另外,调用 O(N) 次 value_type
的构造函数,其中 N 为 cont.size() 。
4) O(N) 次比较,其中 N 为 cont.size() 。
6-8) 常数。
9) O(N) 次比较,其中 N 为 cont.size() 。
另外,调用 O(N) 次 value_type
的构造函数,其中 N 为 cont.size() 。
10) O(N) 次比较,其中 N 为 cont.size() 。
11) 与 other
的大小成线性。
12) 常数。
13) O(N) 次比较,其中 N 为 cont.size() + std::distance(first, last) 。
另外,调用 O(N) 次 value_type
的构造函数,其中 N 为 cont.size() 。
14) O(N) 次比较,其中 N 为 cont.size() + std::distance(first, last) 。
析构 priority_queue
std::priority_queue<T,Container,Compare>::~priority_queue
~priority_queue(); |
销毁容器适配器。调用元素的析构函数,然后解分配所用的存储。注意,若元素是指针,则不销毁所指向的对象。
复杂度
与容器适配器大小成线性。
调用示例
#include <iostream>
#include <forward_list>
#include <string>
#include <iterator>
#include <algorithm>
#include <functional>
#include <queue>
#include <deque>
#include <time.h>
using namespace std;
struct Cell
{
int x;
int y;
Cell() = default;
Cell(int a, int b): x(a), y(b) {}
Cell &operator +=(const Cell &cell)
{
x += cell.x;
y += cell.y;
return *this;
}
Cell &operator +(const Cell &cell)
{
x += cell.x;
y += cell.y;
return *this;
}
Cell &operator *(const Cell &cell)
{
x *= cell.x;
y *= cell.y;
return *this;
}
Cell &operator ++()
{
x += 1;
y += 1;
return *this;
}
bool operator <(const Cell &cell) const
{
if (x == cell.x)
{
return y < cell.y;
}
else
{
return x < cell.x;
}
}
bool operator >(const Cell &cell) const
{
if (x == cell.x)
{
return y > cell.y;
}
else
{
return x > cell.x;
}
}
bool operator ==(const Cell &cell) const
{
return x == cell.x && y == cell.y;
}
};
std::ostream &operator<<(std::ostream &os, const Cell &cell)
{
os << "{" << cell.x << "," << cell.y << "}";
return os;
}
template<typename _Tp, typename _Sequence = vector<_Tp>,
typename _Compare = less<typename _Sequence::value_type> >
void queuePrint(const std::string &name,
const std::priority_queue<_Tp, vector<_Tp>, _Compare> &queue)
{
std::cout << name ;
std::priority_queue<_Tp, vector<_Tp>, _Compare> queuep = queue;
while (queuep.size() > 0)
{
std::cout << queuep.top() << " ";
queuep.pop();
}
std::cout << std::endl;
}
struct Compare
{
Compare() {}
bool operator()(const Cell &a, const Cell &b)const
{
if (a.x == b.x)
{
return a.y < b.y;
}
return a.x < b.x;
}
};
int main()
{
std::cout << std::boolalpha;
std::mt19937 g{std::random_device{}()};
srand((unsigned)time(NULL));
auto generate = []()
{
int n = std::rand() % 10 + 110;
Cell cell{n, n};
return cell;
};
//1) 默认构造函数。值初始化底层容器。
std::priority_queue<Cell> queue1;
std::cout << "queue1 empty: " << queue1.empty() << std::endl;
std::priority_queue<Cell, std::vector<Cell>, Compare> queue3;
std::cout << "queue3 empty: " << queue3.empty() << std::endl;
std::cout << std::endl;
std::vector<Cell> vector1(6);
std::generate(vector1.begin(), vector1.end(), generate);
std::cout << "vector1: ";
std::copy(vector1.begin(), vector1.end(), std::ostream_iterator<Cell>(std::cout, " "));
std::cout << std::endl;
//2) 用 compare 的内容复制构造比较函数对象 comp 。值初始化底层容器 c 。
std::priority_queue<Cell> queue2(std::less<Cell>(), vector1);
queuePrint("queue2: ", queue2);
std::cout << std::endl;
//4) 用 std::move(cont) 移动构造底层容器 c 。
//以 compare 的内容复制构造比较函数对象 comp 。
//调用 std::make_heap(c.begin(), c.end(), comp) 。
std::priority_queue<Cell> queue4(std::less<Cell>(), std::move(vector1));
queuePrint("queue4: ", queue4);
std::cout << std::endl;
//5) 复制构造函数。以 other.c 的内容复制构造底层容器。以 other.comp 复制构造比较函数对象。
std::priority_queue<Cell> queue5(queue2);
queuePrint("queue5: ", queue5);
std::cout << std::endl;
//6) 移动构造函数。以 std::move(other.c) 构造底层容器。
//以 std::move(other.comp) 构造比较函数对象。
std::priority_queue<Cell> queue6(std::move(queue2));
queuePrint("queue6: ", queue6);
std::cout << std::endl;
std::vector<Cell> vector2(6);
std::generate(vector2.begin(), vector2.end(), generate);
std::cout << "vector2: ";
std::copy(vector2.begin(), vector2.end(), std::ostream_iterator<Cell>(std::cout, " "));
std::cout << std::endl;
//13) 从 cont 复制构造 c 并从 compare 复制构造 comp 。
//然后调用 c.insert(c.end(), first, last);
//再调用 std::make_heap(c.begin(), c.end(), comp);
std::priority_queue<Cell> queue7(vector2.begin(), vector2.end());
queuePrint("queue7: ", queue7);
std::cout << std::endl;
return 0;
}
输出