queue队列容器
困难7队列(queue):就像排队买奶茶,先来的先得!
想象一下,你和小伙伴们在学校门口排队买奶茶:第一个到的人先拿到奶茶,然后离开队伍;后面来的人只能排在队伍末尾,等前面所有人都买完才能轮到自己。这种“先进先出”(First In First Out, FIFO)的规则,在计算机编程中就是队列(queue)。
C++ 的 queue 容器就是专门帮我们管理这种“排队”情况的工具。使用它之前,需要先引入头文件:
#include <queue>
队列的核心操作:排队五步走
队列就像一支队伍,队伍只有两个关键位置:队首(第一个)和队尾(最后一个)。常见的操作有:
push(x):把一个人(或数据)放到队伍最后面。front():看一眼队首是谁,但不让他离开。pop():让队首的人离开队伍(通常要先看一眼再移除)。empty():检查队伍是不是空的(没人排队了)。size():数一数队伍里有多少人。
⚠️ 注意:
queue没有back()查看队尾?其实也有,不过最常用的是front()。如果想看队尾,可以用back()。
举个生活例子:模拟排队打饭
假设中午食堂有三位同学来排队:小红、小明、小华。我们用代码模拟这个场景:
#include <iostream>
#include <queue>
using namespace std;
int main() {
queue<string> line; // 创建一个队列,里面存字符串(名字)
// 三位同学依次加入队伍
line.push("小红"); // 小红先到,排在第一位
line.push("小明"); // 小明后到,排在小红后面
line.push("小华"); // 小华最后到,排在最后
cout << "当前队伍有 " << line.size() << " 个人" << endl; // 3人
cout << "队首的是:" << line.front() << endl; // 小红
line.pop(); // 小红打好饭离开了
cout << "现在队首的是:" << line.front() << endl; // 小明
// 让剩下的人依次离开
while (!line.empty()) {
cout << line.front() << " 离开了" << endl;
line.pop();
}
cout << "队伍空了?" << (line.empty() ? "是的" : "没有") << endl;
return 0;
}
运行结果:
当前队伍有 3 个人
队首的是:小红
现在队首的是:小明
小明 离开了
小华 离开了
队伍空了?是的
队列的“长相”:只能用头部和尾部
queue 是一个受限的线性表——你只能从一端(队尾)添加,从另一端(队首)删除。你不能像数组那样随意查看中间的元素。这跟现实中的排队一模一样:你不能插队,也不能直接看队伍中间的人是谁(除非从头一个个数过去)。
生活中的队列应用
- 打印机任务队列:你和其他同学同时提交打印任务,打印机按照提交顺序依次打印。先点打印的同学先拿到文件。
- 键盘缓冲区:你快速按下一串按键,比如“h e l l o”,计算机会按照你按的顺序依次处理,就像排好队的字母。
- 游戏中的操作序列:比如格斗游戏中你连按“上、下、左、右”四个方向,系统会按顺序执行,不会乱掉。
- 银行叫号系统:先取号的人先被叫到窗口办理业务。
新手容易犯的错误
1. 对空队列使用 front() 或 pop()
queue<int> q;
cout << q.front(); // 错误!队列为空,访问队首会导致程序崩溃
q.pop(); // 同样错误!空队列不能删除元素
正确做法:先检查 empty() 再操作。
2. 忘记 pop() 会让队列永远删不掉
有时候我们只看了 front(),但忘记调用 pop(),结果队首一直占着位置,后面的元素永远出不来。就像排队时第一个人赖着不走,后面的人永远买不到东西。
queue<string> q;
q.push("A");
q.push("B");
// 错误:只看了front但没pop
string first = q.front(); // first = "A"
// 如果后面一直不pop,B永远出不来
3. 混淆 queue 和 stack
queue 是先进先出(FIFO),stack 是后进先出(LIFO)。别搞混了!想象一下:
- 队列:排队打饭 → 先来的先吃
- 堆栈:一摞盘子 → 最后放上去的盘子最先被拿走
完整示例:模拟“叫号系统”
下面是一个完整的叫号系统:用户输入5个数字(也可以直接写死),然后按照先进先出的顺序依次输出。
#include <iostream>
#include <queue>
using namespace std;
int main() {
queue<int> callNumber; // 创建整数队列,存放号码
cout << "请输入5个号码(每输入一个按回车): " << endl;
for (int i = 0; i < 5; i++) {
int num; // 临时变量存储输入的号码
cin >> num;
callNumber.push(num); // 号码加入队尾
}
cout << "叫号顺序如下:" << endl;
int index = 1; // 叫号序号
while (!callNumber.empty()) {
cout << "第" << index << "位请到窗口办理,号码:" << callNumber.front() << endl;
callNumber.pop(); // 办理完离开
index++;
}
cout << "所有号码已叫完,队伍空了。" << endl;
return 0;
}
如果你不想手动输入,可以把上面的 cin 换成直接写死的值,比如:
// 直接往队列里加5个号码
callNumber.push(101);
callNumber.push(102);
callNumber.push(103);
callNumber.push(104);
callNumber.push(105);
小练习(试试看)
- 修改上面的叫号系统,改为先输出“当前队伍有多少人”,再逐一叫号。
- 用
queue模拟“电梯等待队列”:假设电梯一次只能进一个人,初始化3个人在电梯外排队,依次进入电梯,每次进入后输出当前电梯内人数和等待人数。 - 思考:如果我们要实现一个“双端队列”(可以从前/后两端插入和删除),应该用哪个容器?(提示:
deque)
相关知识点指引
deque(双端队列):允许从队列两端插入和删除,比queue更灵活。stack(堆栈):先进后出,和queue正好相反,常用于括号匹配、撤销操作等。priority_queue(优先队列):不是普通排队,而是按优先级排序,优先级高的先出队(比如急诊病人优先就诊)。- STL 容器对比:
queue底层默认用deque实现,但也可以改用list。理解底层结构能帮你更好地选择容器。
队列虽然简单,但它是很多复杂算法(如广度优先搜索 BFS)的基础。掌握好队列,你就能轻松模拟现实中的各种排队场景啦!
例题精讲
在C++ STL中,queue容器默认的底层容器是?
执行如下代码后,输出结果是什么? queue<int> q; q.push(1); q.push(2); q.push(3); q.pop(); cout << q.front();
C++ STL中的queue容器支持通过下标运算符[]随机访问元素。
请补全函数,使其返回队列中元素的个数。
int getSize(queue<int>& q) {
return ___;
}以下程序试图输出队列中的所有元素(空格分隔),但缺少一行代码,请补全。
queue<int> q;
q.push(10); q.push(20); q.push(30);
while (!q.empty()) {
cout << q.front() << " ";
___;
}