重点总结:
std::queue
是一个先进先出(FIFO)容器适配器,故 std::queue 不提供元素的任何迭代器操作。std::deque
和std::list
满足FIFO操作需求。queue底层默认使用std::deque
。std::queue
容器只能访问头元素和尾元素。只能在容器的末尾添加新元素,只能从头部移除元素。
std::priority_queue
是一种容器适配器,根据严格的弱排序准则,它的第一个元素总是它所包含的元素中最大的。std::priority_queue
默认情况下,如果没有为特定优先级队列类实例化指定容器类,底层默认使用std::vector
。
1. std::queue
1.1 构造函数
std::queue
底层容器可以是标准容器类模板之一,也可以是其他特定设计的容器类。该底层容器应至少支持以下操作:
empty(),size(),front(),back(),push_back(),pop_front()
,STL中deque
和list
满足这些要求。默认情况下,如果没有为特定队列类实例化指定容器类,则使用标准容器deque
。
-
#include<queue>
-
queue
构造函数有如下几种类型www.cplusplus.com。
[1]. 通过容器对象进行构造 [2]. 同上,参数为右值 [3]. std::allocator对象作为参数 [4]. 通过容器对象、std::allocator进行构造 [5]. 同上,参数`ctnr`为 [6]. 复制构造 with std::allocator [7]. 移动构造 with std::allocator
int main () {
std::deque<int> mydeck(3,100); // deque with 3 elements
std::list<int> mylist(2,200); // list with 2 elements
std::queue<int> first; // empty queue
std::queue<int> second(mydeck); // [1]. 复制构造,通过deque
std::queue<int,std::list<int> > third; // empty queue with list as underlying container
std::queue<int,std::list<int> > fourth(mylist);
std::cout << "size of first: " << first.size() << '\n';
std::cout << "size of second: " << second.size() << '\n';
std::cout << "size of third: " << third.size() << '\n';
std::cout << "size of fourth: " << fourth.size() << '\n';
return 0;
}
size of first: 0
size of second: 3
size of third: 0
size of fourth: 2
1.2 常用函数
常用函数如下图,本小节按图中函数名称顺序,依次函数进行介绍:
- <1>.
back()
返回尾元素引用。front()
返回头元素引用,原型如下:
reference& back();
const_reference& back() const;
reference& front();
const_reference& front() const;
测试代码:
int main () {
std::queue<int> myqueue;
myqueue.push(12);
myqueue.push(75); // this is now the back
myqueue.back() -= myqueue.front();
std::cout << "myqueue.back() is now " << myqueue.back() << '\n';
return 0;
}
myqueue.back() is now 63
- <2>.I.
emplace()
在容器尾部添加元素,move。
II.push()
在容器尾部添加元素,copy/move。
III.pop()
删除容器头元素,函数原型如下:
template <class... Args> void emplace(Args&&... args); // emplace
void push(const value_type& val); // push
void push(value_type&& val);
void pop(); // pop
测试代码:
int main () {
std::queue<int> myints;
myints.push(1);
myints.push(2);
myints.emplace(3);
myints.emplace(4);
while (!myints.empty()){
std::cout << myints.front() << " ";
myints.pop();
}
return 0;
}
1 2 3 4
- <3>.
empty()
返回容器是否为空,size()
返回容器元素个数。,原型如下:
bool empty() const;
size_type size() const;
测试代码:
int main () {
std::queue<int> myints;
std::cout << "myints. empty: " << myints.empty() << '\n';
std::cout << "myints. size: " << myints.size() << '\n';
for (int i=0; i<5; i++)
myints.push(i);
std::cout << "myints. empty: " << myints.empty() << '\n';
std::cout << "myints. size: " << myints.size() << '\n';
return 0;
}
myints. empty: 1
myints. size: 0
myints. empty: 0
myints. size: 5
- <4>.
swap()
,将本容器中的元素与参数容器中的元素互换,原型如下:
void swap (queue& x) noexcept(/*see below*/);
测试代码:
int main () {
std::queue<int> foo,bar;
foo.push (10); foo.push(20); foo.push(30);
bar.push (111); bar.push(222);
foo.swap(bar);
std::cout << "size of foo: " << foo.size() << '\n';
std::cout << "size of bar: " << bar.size() << '\n';
return 0;
}
size of foo: 2
size of bar: 3
2. std::priority_queue
2.1 简介
std::vector
和std::deque
满足priority_queue
底层功能要求。默认情况下,如果没有为特定优先级队列类实例化指定容器类,则其底层实现使用std::vector
。
为了始终在其内部保持堆结构(其内部默认是大顶堆),需要支持随机访问迭代器。这是由容器适配器自动完成的,在需要时自动调用算法函数make_heap
、push_heap
和pop_heap
,
priority_queue
与queue
不同点在于我们可以自定义其中数据的优先级, 让优先级高的排在队列前面,优先出队。默认情况下大的元素在前。
2.2 常用函数
-
<1> .
priority_queue
常用函数如下图,和std::queue
功能相同。
top() 访问队头元素 empty() 队列是否为空 size() 返回队列内元素个数 push() 插入元素到队尾 (并排序) emplace() 原地构造一个元素并插入队列 pop() 弹出队头元素 swap() 交换内容
2.3 构造函数
stl_queue.h中有如下定义:
template<typename _Tp,
typename _Sequence = vector<_Tp>,
typename _Compare = less<typename_Sequence::value_type> >
class priority_queue { …
××××××××××××××××××××× 很重要 ×××××××××××××××××××××
其中,_Tp
为数据类型,_Sequence
是容器类型(必须是用数组实现的容器,如 vector,deque等等,但不能用 list。STL里面默认用的是vector),_Compare
是比较函数(default: less<T>
)。小顶堆使用std::greater<T>
。
当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆。如下所示:
std::priority_queue<int> pri_queue; // 默认大顶堆
priority_queue<int, vector<int>, less<int>> pri_queue_temp; // 与上面这句功能相同
priority_queue<int, vector<int>, greater<int>> pri_queue_temp; // 小顶堆
优先级的队列构造函数有五种类型,主要使用的有以下两种:
- [1]. 无输入参数,
stl_queue.h
中源码如下所示。
explicit
priority_queue(const _Compare& __x = _Compare(),
_Sequence&& __s = _Sequence()) : c(std::move(__s)), comp(__x) {
std::make_heap(c.begin(), c.end(), comp); }
测试代码:
#include <iostream> // std::cout
#include <queue> // std::priority_queue
#include <vector> // std::vector
#include <functional> // std::greater, std::less
int main() {
// 以下两句相同
std::priority_queue<int> pri_queue;
priority_queue<int, vector<int>, less<int>> pri_queue_temp;
pri_queue.push(1); pri_queue.push(3); pri_queue.push(2);
while (!pri_queue.empty())
{
cout << pri_queue.top() << ' ';
pri_queue.pop();
}
cout << endl; // 打印: 3 2 1
return 0;
}
- [2]. 通过迭代器
[first,last)
构造对象,stl_queue.h
中源码如下所示。
template<typename _InputIterator>
priority_queue(_InputIterator __first, _InputIterator __last,
const _Compare& __x = _Compare(),
_Sequence&& __s = _Sequence()) : c(std::move(__s)), comp(__x) {
__glibcxx_requires_valid_range(__first, __last);
c.insert(c.end(), __first, __last);
std::make_heap(c.begin(), c.end(), comp);
}
测试代码:
#include <iostream> // std::cout
#include <queue> // std::priority_queue
#include <vector> // std::vector
#include <functional> // std::greater, std::less
int main() {
int myints[]= {
10,60,50,20};
// 以下两句相同
std::priority_queue<int> second(myints,myints+4);
std::priority_queue<int, std::vector<int>, std::greater<int>> third(myints,myints+4);
while (!second.empty())
{
cout << second.top() << ' ';
second.pop();
}
cout << endl; // 打印结果 60 50 20 10
return 0;
}
2.4 自定义类型作为元素
- 自定义类型作为元素 需要满足两个条件。
- (a). 自定义类型的对象中需 重载
operator<
函数,如果是基础类型(已定义operator<
),无需这一条件。 - (b). 同时需要重写仿函数
operator()
代替_Compare
函数,代码如下:
class TestClass {
public:
int x;
TestClass(int a) {
x = a;}
// 1. 自定义类型需,运算符重载<
bool operator<(const TestClass& a) const{
return x < a.x;
}
};
class Test_func {
public:
// 2. 重写仿函数 operator()
bool operator() (TestClass a, TestClass b) {
return a.x < b.x;
}
};
int main() {
// [1]. 使用 priority_queue<TestClass>
priority_queue<TestClass> queue_;
queue_.emplace(TestClass(1));
queue_.emplace(TestClass(3));
queue_.emplace(TestClass(2));
std::cout << "queue_: ";
while (!queue_.empty())
{
cout << queue_.top().x;
queue_.pop();
}
// [2]. 与上述[1]相同
priority_queue<TestClass, vector<TestClass>, Test_func> queue_temp;
queue_temp.emplace(TestClass(1));
queue_temp.emplace(TestClass(3));
queue_temp.emplace(TestClass(2));
std::cout << "\n queue_temp:";
while (!queue_temp.empty())
{
cout << queue_temp.top().x;
queue_temp.pop();
}
return 0;
}
queue_: 321
queue_temp:321