CC++ & Algorithm

queue队列容器

困难7
语言版本:C++
概述:queue就像排队买汉堡,先来的人先买到,后来的人只能排在后面——这就是“先进先出”。

队列(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. 混淆 queuestack

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);

小练习(试试看)

  1. 修改上面的叫号系统,改为先输出“当前队伍有多少人”,再逐一叫号。
  2. queue 模拟“电梯等待队列”:假设电梯一次只能进一个人,初始化3个人在电梯外排队,依次进入电梯,每次进入后输出当前电梯内人数和等待人数。
  3. 思考:如果我们要实现一个“双端队列”(可以从前/后两端插入和删除),应该用哪个容器?(提示:deque

相关知识点指引

  • deque(双端队列):允许从队列两端插入和删除,比 queue 更灵活。
  • stack(堆栈):先进后出,和 queue 正好相反,常用于括号匹配、撤销操作等。
  • priority_queue(优先队列):不是普通排队,而是按优先级排序,优先级高的先出队(比如急诊病人优先就诊)。
  • STL 容器对比queue 底层默认用 deque 实现,但也可以改用 list。理解底层结构能帮你更好地选择容器。

队列虽然简单,但它是很多复杂算法(如广度优先搜索 BFS)的基础。掌握好队列,你就能轻松模拟现实中的各种排队场景啦!

例题精讲

1单选题

在C++ STL中,queue容器默认的底层容器是?

Avector
Bdeque
Clist
Darray
2单选题

执行如下代码后,输出结果是什么? queue<int> q; q.push(1); q.push(2); q.push(3); q.pop(); cout << q.front();

A1
B2
C3
D未定义行为
3判断题

C++ STL中的queue容器支持通过下标运算符[]随机访问元素。

4填空题
请补全函数,使其返回队列中元素的个数。

int getSize(queue<int>& q) {
    return ___;
}
5填空题
以下程序试图输出队列中的所有元素(空格分隔),但缺少一行代码,请补全。

queue<int> q;
q.push(10); q.push(20); q.push(30);
while (!q.empty()) {
    cout << q.front() << " ";
    ___;
}