买冰凌排队:先来的人先买到——"先进先出"。
想象排队买冰凌:新来的只能站到队尾(入队 enqueue),卖冰凌的只服务队头那个人(出队 dequeue),服务完他就离开——先来先走,这叫先进先出(FIFO,First In First Out)。上一课的栈是"一摞便当盒"(后放先走、只有一个口);队列是"一条队"(先放先走、两个口:队尾进、队头出)。
规则:dequeue 永远弹出队头(最先入队、还没出队的那个人)。跟着操作推演:
// 初始:队空 enqueue A enqueue B enqueue C dequeue // → ? dequeue // → ? dequeue // → ?
普通数组队列的做法:入队 rear 往后挪,出队 front 往后挪,谁也不回头。跟着下面这组操作走一遍(容量 5,数组 a[0..4]):
// 容量 5:a[0] a[1] a[2] a[3] a[4] enqueue 小明 // front=0 rear=0 enqueue 小红 // rear=1 enqueue 小强 // rear=2 enqueue 小磊 // rear=3 enqueue 小兰 // rear=4,队满(5 人) dequeue 小明 // front=1 dequeue 小红 // front=2 enqueue 小刚 // ?
走到最后一步:队里其实只剩 3 个人(小强、小磊、小兰),a[0]、a[1] 都空着;但 rear 已经顶到 a[4],右边没有格子了——按"rear+1 越界 = 队满"的判断,小刚进不来!这就是假死:看着满了,其实还有空位,只是空位在"前面",用不上。
两条出路:
核心思想:下标 +1 之后如果到达容量 n,就用 (i+1) % n 绕回 0——像过山车🎢的环形轨道,跑完最后一格回到第一格。规则(容量 n,front = 队头下标,rear = 队尾下标,front = -1 表示队空):
(rear+1) % n == front → 队满(下一格就是队头,再放会撞上);否则 rear = (rear+1) % n,a[rear] = x;若 front == -1 则 front = rear。x = a[front];若 front == rear(只剩这一个)→ front = rear = -1(变空);否则 front = (front+1) % n。完整走一遍(容量 6):入队 1、2、3,出队、出队,再入队 4、5、6、7、8:
// n = 6,front = rear = -1(空) enqueue 1 // (rear+1)%6=0 != -1 → rear=0, a[0]=1, front=0 enqueue 2 // rear=1, a[1]=2 enqueue 3 // rear=2, a[2]=3 dequeue // 弹出 a[0]=1,front=1 dequeue // 弹出 a[1]=2,front=2(队里只剩 3) enqueue 4 // (2+1)%6=3 != 2 → rear=3, a[3]=4 enqueue 5 // rear=4, a[4]=5 enqueue 6 // rear=5, a[5]=6 enqueue 7 // (5+1)%6=0 != 2 → rear=0,a[0]=7 ← 绕回队头! enqueue 8 // (0+1)%6=1 != 2 → rear=1,a[1]=8
注意最后两步:rear 走到 a[5] 后,% 6 把它弹回了 a[0],把当初"出队腾出来的"格子又用上了——不再需要搬家!
场景:4 个同学的打印任务先后到达,打印机一次处理一份。处理完前 2 份后,又有 2 个新任务加入。处理顺序应该完全按到达顺序(先进先出),这正是队列的本行。用容量 6 的循环队列模拟:
入队:小明、小红、小强、小美 出队(打印)1 份 出队(打印)1 份 入队:小磊、小兰 把剩下的全部出队打印
为什么这里必须是队列而不是栈?如果用栈,最后提交的小兰会第一个被打印——共享设备"先来后到"的公平性就没了。
// 循环队列(容量 6)+ 打印机任务模拟 // 输出:小明 小红 小强 小美 小磊 小兰(按到达顺序打印) #include <iostream> #include <string> using namespace std; const int N = 6; string a[N]; int front = -1, rear = -1; // front = -1 表示队空 bool empty() { return front == -1; } bool full() { return (rear + 1) % N == front; } void push(string x) { rear = (rear + 1) % N; // % N 实现绕圈 a[rear] = x; if (front == -1) front = rear; } string pop() { string x = a[front]; if (front == rear) front = rear = -1; // 最后一个出队 → 变空 else front = (front + 1) % N; return x; } int main() { push("小明"); push("小红"); push("小强"); push("小美"); cout << "打印:" << pop() << endl; cout << "打印:" << pop() << endl; push("小磊"); push("小兰"); while (!empty()) cout << "打印:" << pop() << endl; return 0; }
% n 绕回队头;空 = front == -1,满 = (rear+1) % n == front。