44 C++ STL模板库13-容器5-容器适配器-队列(queue)
C++ STL模板库13-容器5-容器适配器-队列(queue)
文章目录
- C++ STL模板库13-容器5-容器适配器-队列(queue)
- 1. 成员类型
- 2. 构造函数
- 3. 容量函数
- 4. 元素访问函数
- 5. 添加元素函数
- 6. 移除元素函数
- 7. 赋值操作符
- 8. 交换函数
- 9. 非成员比较操作符
- 10. 非成员交换函数
- 11. 注意事项
- 12. 示例用法
- 关键操作
队列(
std::queue
)是一个容器适配器(container adapter),它基于其他容器(如
std::deque
或
std::list
)实现先进先出(FIFO)的行为。队列本身不是一个独立的容器,而是一个适配器类模板,定义在头文件
<queue>
中。队列的操作主要关注元素的添加(在队尾)、移除(在队首)和访问。
1. 成员类型
这些类型在模板中定义,用于泛型编程。
类型名称 | 描述 |
---|---|
value_type | 队列中元素的类型(例如,T )。 |
container_type | 底层容器的类型(默认为std::deque<T> )。 |
size_type | 用于表示大小的无符号整数类型(通常为std::size_t )。 |
reference | 元素的引用类型(例如,value_type& )。 |
const_reference | 元素的常量引用类型(例如,const value_type& )。 |
2. 构造函数
队列的底层容器可通过这些构造函数指定。
函数签名 | 说明 |
---|---|
queue() | 默认构造函数,创建一个空队列。 |
explicit queue(const container_type& cont) | 用现有容器cont 初始化队列。 |
explicit queue(container_type&& cont) | 用移动语义初始化队列(C++11起)。 |
queue(const queue& other) | 拷贝构造函数。 |
queue(queue&& other) | 移动构造函数(C++11起)。 |
3. 容量函数
这些函数用于查询队列状态,时间复杂度为O(1)。
函数签名 | 说明 |
---|---|
bool empty() const | 检查队列是否为空(返回true 如果空)。 |
size_type size() const | 返回队列中元素的数量。 |
4. 元素访问函数
访问元素不修改队列,但需确保队列非空,否则行为未定义。
函数签名 | 说明 |
---|---|
reference front() | 返回队首元素的引用(第一个添加的元素)。 |
const_reference front() const | 常量版本的队首访问。 |
reference back() | 返回队尾元素的引用(最后一个添加的元素)。 |
const_reference back() const | 常量版本的队尾访问。 |
5. 添加元素函数
这些函数添加元素后,队列大小增加。
函数签名 | 说明 |
---|---|
void push(const value_type& value) | 在队尾添加一个元素(拷贝语义)。 |
void push(value_type&& value) | 在队尾添加一个元素(移动语义,C++11起)。 |
template <class... Args> void emplace(Args&&... args) | 在队尾直接构造元素(避免拷贝,C++11起)。 |
6. 移除元素函数
移除操作后,队列大小减少;需确保队列非空。
void pop()
: 移除队首元素(不返回被移除元素)。
7. 赋值操作符
用于将一个队列的内容赋给另一个队列。
函数签名 | 说明 |
---|---|
queue& operator=(const queue& other) | 拷贝赋值操作符。 |
queue& operator=(queue&& other) | 移动赋值操作符(C++11起)。 |
8. 交换函数
高效交换底层容器,不影响元素所有权。
函数签名 | 说明 |
---|---|
void swap(queue& other) noexcept | 交换两个队列的内容(C++11起支持noexcept)。 |
9. 非成员比较操作符
这些全局函数基于底层容器的比较实现。
函数签名 | 说明 |
---|---|
bool operator==(const queue& lhs, const queue& rhs) | 检查两个队列是否相等。 |
bool operator!=(const queue& lhs, const queue& rhs) | 检查是否不等。 |
bool operator<(const queue& lhs, const queue& rhs) | 检查是否小于(字典序比较)。 |
bool operator<=(const queue& lhs, const queue& rhs) | 检查是否小于或等于。 |
bool operator>(const queue& lhs, const queue& rhs) | 检查是否大于。 |
bool operator>=(const queue& lhs, const queue& rhs) | 检查是否大于或等于。 |
10. 非成员交换函数
提供一致的交换接口。
void swap(queue<T, Container>& lhs, queue<T, Container>& rhs) noexcept
: 全局swap函数,等同于lhs.swap(rhs)
(C++11起)。
11. 注意事项
- 队列的特性:队列是一个适配器,默认底层容器为
std::deque
,但可通过模板参数指定其他容器(如std::list
),要求容器支持back()
,front()
,push_back()
,pop_front()
等操作。 - 注意事项:队列不支持随机访问(如索引操作),所有操作的时间复杂度均为O(1),但依赖于底层容器。使用时需包含头文件
#include <queue>
。
12. 示例用法
-
示例1:
#include <iostream> #include <queue> #include <list> #include <string>using namespace std; int main (void) {// queue<string, list<string> > qs;queue<string> qs;qs.push ("不");qs.push ("尽");qs.push ("长江");qs.push ("滚滚");qs.push ("来");while (! qs.empty ()) {cout << qs.front ();qs.pop ();}cout << endl;return 0; }
输出结果: 不尽长江滚滚来
-
示例2:
#include <iostream> #include <queue> // 必须包含的头文件int main() {// 1. 创建队列std::queue<int> q; // 默认底层容器为 deque// 2. 添加元素(队尾)q.push(10); // 拷贝添加q.push(20); q.emplace(30); // 直接构造(C++11)q.emplace(40); // 3. 访问元素std::cout << "队首元素: " << q.front() << "\n"; // 10std::cout << "队尾元素: " << q.back() << "\n"; // 40// 4. 移除元素(队首)q.pop(); // 移除10std::cout << "新队首: " << q.front() << "\n"; // 20// 5. 容量查询std::cout << "元素数量: " << q.size() << "\n"; // 3std::cout << "是否为空: " << (q.empty() ? "是" : "否") << "\n"; // 否// 6. 交换队列std::queue<int> other;other.push(99); q.swap(other); std::cout << "交换后队首: " << q.front() << "\n"; // 99// 7. 遍历队列(会清空队列)std::cout << "遍历结果: ";while (!q.empty()) {std::cout << q.front() << " ";q.pop(); // 边访问边移除} // 输出: 99return 0; }
关键操作
-
特殊技巧
-
批量初始化:
std::deque<int> init{1,2,3}; std::queue<int> q(init); // 通过底层容器初始化
-
移动语义(C++11):
std::queue<int> q2(std::move(q)); // 移动而非拷贝
-
-
底层容器
可指定不同底层容器:std::queue<int, std::list<int>> listQueue; // 基于list
要求容器支持:
back()
,push_back()
,pop_front()
-
遍历注意
队列没有迭代器,遍历需结合:while (!q.empty()) {process(q.front()); // 处理队首q.pop(); // 移除已处理元素 }
-
实践建议:
- 优先使用
emplace()
避免拷贝开销 - 访问元素前必须用
empty()
检查 - 需要保留数据时,先拷贝再遍历(
auto temp = q;
) - 对性能敏感时考虑直接使用底层容器(如
deque
)
- 优先使用