更多 C++语法知识在 C++语言学记专栏
往期 STL 容器看点:
这篇文章是关于 C++所有数据结构概览中的单独专题
顺序容器 vector array list deque forward_list 关联容器 set&multiset map&multimap 无序关联容器 Unordered set&multiset Unordered map&multimap 容器适配器 stack queue priority_queue 其他容器 string
std::queue(队列)和 std::stack(栈)一样,也是 C++ 标准模板库(STL)中的一个容器适配器。但它实现的是**“先进先出”(First-In, First-Out, FIFO)**的数据结构。你可以把它想象成一个排队买票的队伍:最早来排队的人最先买到票离开,新来的人只能排在队尾。
1. std::queue 的基本使用语法
要使用 queue,首先需要包含头文件 <queue>。
#include <iostream>
#include <queue>
#include <string>
1.1 声明和初始化
std::queue 也是一个模板类,在创建时需要指定存储的元素类型。
// 创建一个存储 int 类型的队列
std::queue<int> q1;
// 创建一个存储 std::string 类型的队列
std::queue<std::string> q2;
1.2 核心成员函数
std::queue 的接口同样非常直观,完全服务于“先进先出”的原则。
| 函数名 | 功能描述 |
|---|---|
push(element) | 将一个元素 element 添加到队尾(入队)。 |
pop() | 移除队首元素(出队)。注意:这个函数也没有返回值。 |
front() | 返回对队首元素的引用。注意:它只返回,不移除。 |
back() | 返回对队尾元素的引用。 |
empty() | 检查队列是否为空。如果为空,返回 true;否则返回 false。 |
size() | 返回队列中元素的数量。 |
与 stack 的关键区别:
-
stack有top()来访问栈顶(也就是最后进入的元素)。 -
queue有front()访问队首(最先进入的元素)和back()访问队尾(最后进入的元素)。
1.3 代码示例
下面是一个完整的例子,展示了 queue 的基本操作:
#include <iostream>
#include <queue>
#include <string>
int main() {
// 1. 创建一个空队列,用于存放字符串
std::queue<std::string> myQueue;
// 2. 使用 empty() 检查队列是否为空
if (myQueue.empty()) {
std::cout << "Queue is initially empty." << std::endl;
}
// 3. 使用 push() 向队尾添加元素
std::cout << "Pushing 'Alice', 'Bob', 'Charlie' into the queue..." << std::endl;
myQueue.push("Alice");
myQueue.push("Bob");
myQueue.push("Charlie");
// 4. 使用 size() 查看队列中元素数量
std::cout << "Current queue size: " << myQueue.size() << std::endl; // 输出: 3
// 5. 使用 front() 和 back() 访问队首和队尾元素
// 队列内元素顺序 (从头到尾): "Alice", "Bob", "Charlie"
std::cout << "Front element is: " << myQueue.front() << std::endl; // 输出: Alice
std::cout << "Back element is: " << myQueue.back() << std::endl; // 输出: Charlie
// 6. 使用 pop() 移除队首元素
std::cout << "Popping the front element..." << std::endl;
myQueue.pop(); // "Alice" 出队
// 再次访问队首元素
std::cout << "Now the front element is: " << myQueue.front() << std::endl; // 输出: Bob
std::cout << "Current queue size: " << myQueue.size() << std::endl; // 输出: 2
// 7. 遍历并清空队列
std::cout << "Popping all elements: ";
while (!myQueue.empty()) {
std::cout << myQueue.front() << " "; // 访问队首
myQueue.pop(); // 移除队首
}
std::cout << std::endl; // 输出: Bob Charlie
// 检查队列是否已清空
if (myQueue.empty()) {
std::cout << "Queue is now empty." << std::endl;
}
// 重要:对空队列调用 front(), back() 或 pop() 是未定义行为,会导致程序崩溃
// myQueue.front(); // 这行代码会引发错误!
return 0;
}
关键点总结:
-
push()在队尾添加元素。 -
pop()从队首移除元素。 -
获取并移除队首元素需要两步:先用
front()获取值,再用pop()移除。 -
同样,在调用
front()、back()或pop()前,务必用empty()进行检查。
2. std::queue 的底层知识
std::queue 和 std::stack 在设计理念上是相同的,它也是一个容器适配器。
2.1 容器适配器
std::queue 同样包装了另一个序列容器,并限制其接口,使其只能进行 FIFO 操作。它本身不负责内存管理。
2.2 底层容器(Underlying Container)
std::queue 的底层容器必须支持以下操作:
-
front():访问第一个元素。 -
back():访问最后一个元素。 -
push_back():在末尾添加元素。 -
pop_front():从头部移除元素。 -
empty():检查是否为空。 -
size():返回大小。
std::queue 的操作与底层容器的映射关系如下:
-
queue::push()内部调用container::push_back()。 -
queue::pop()内部调用container::pop_front()。 -
queue::front()内部调用container::front()。 -
queue::back()内部调用container::back()。
2.3 默认的底层容器:std::deque
和 std::stack 一样,std::queue 默认使用的底层容器也是 std::deque(双端队列)。
为什么默认是 std::deque?这次的原因更加关键!
-
为什么不能是
std::vector?std::vector不支持高效的pop_front()操作。要在vector的头部移除一个元素,必须将它后面的所有元素都向前移动一位。如果vector中有 N 个元素,这个操作的时间复杂度是 O(N),效率极低。因此,std::vector不能作为std::queue的底层容器。
-
std::list(双向链表) vsstd::deque(双端队列)-
std::list:它支持高效的push_back()和pop_front()操作,时间复杂度都是 O(1)。所以std::list可以作为std::queue的底层容器。 -
std::deque:它被设计为在两端进行添加和删除都非常高效。它的push_back()和pop_front()操作的平摊时间复杂度也是 O(1)。 -
deque胜出的原因:与list相比,deque的内存布局更加紧凑(由连续的内存块组成),这使得它的缓存命中率更高,通常在实际性能上优于list。因此,std::deque成为了std::queue的默认选择。
-
2.4 更换底层容器
你可以显式地将 std::queue 的底层容器指定为 std::list。
std::queue 的模板定义如下:
template<
class T,
class Container = std::deque<T>
> class queue;
示例:使用 std::list 作为底层容器
#include <list>
#include <queue>
#include <iostream>
// 声明一个使用 std::list<int> 作为底层容器的队列
std::queue<int, std::list<int>> list_based_queue;
list_based_queue.push(100);
list_based_queue.push(200);
std::cout << "Front: " << list_based_queue.front() << std::endl; // 输出: 100
list_based_queue.pop();
std::cout << "Front after pop: " << list_based_queue.front() << std::endl; // 输出: 200
总结
-
是什么:
std::queue是一个实现 FIFO(先进先出)策略的容器适配器。 -
怎么用:通过
push()(入队)、pop()(出队)、front()(访问队首)、back()(访问队尾)等函数操作。 -
底层是什么:它包装了一个序列容器来存储数据。
-
默认底层容器:
std::deque,因为它在两端的增删操作都非常高效,且内存性能通常优于std::list。 -
不可用
vector:std::vector因为没有高效的头部删除操作,所以不能作为std::queue的底层容器。 -
可定制:如果特定场景下有需求(例如,频繁的插入删除导致
deque性能下降),可以将底层容器更换为std::list。
1145

被折叠的 条评论
为什么被折叠?



