跳转至

栈和队列

方法速览

任务 方法 口诀
后进先出 LIFO,只在栈顶进出 后进先出
队列 先进先出 FIFO,队尾进、队头出 先进先出
出栈序列判定 按目标序列逐个“入栈到它 → 弹出它”模拟,卡住即非法 缺谁进谁,进了就弹
循环队列 下标取模 (rear+1) % N;判满常用“牺牲一格” 转圈取模,留空判满
双栈当队列 入队压 s1;出队时若 s2 空就把 s1 整体倒进 s2 倒一次序就翻过来

概念与数组实现

(stack):只允许在同一端(栈顶)插入删除——后进先出(LIFO)。 队列(queue):队尾入、队头出——先进先出(FIFO)。

数组实现(栈):top 指向栈顶元素下标:

1
2
3
int stk[N], top = 0;      // top = 0 表示空
stk[++top] = x;           // push:先加再存
x = stk[top--];           // pop:先取再减

数组实现(循环队列):头尾下标都取模绕圈,防假溢出:

1
2
3
int q[N], head = 0, rear = 0;
q[rear] = x; rear = (rear + 1) % N;   // 入队(rear 指向下一个空位)
x = q[head]; head = (head + 1) % N;   // 出队

判满判空(牺牲一格法,容量 N 的数组存 N−1 个):

  • 队空:head == rear
  • 队满:(rear + 1) % N == head
  • 元素个数:(rear - head + N) % N

STL 实现

stack<int> s;        s.push(x); x = s.top(); s.pop(); s.empty(); s.size();
queue<int> q;        q.push(x); x = q.front(); q.pop();

注意:栈顶用 top()、队头用 front()pop() 只删不返回值,取值与弹出分两步。priority_queue 默认大根堆

双栈实现队列

两个栈 s1(入)、s2(出):

  • 入队:压进 s1;
  • 出队:s2 非空则弹 s2 栈顶;s2 为空则把 s1 全部弹出依次压入 s2(顺序颠倒一次),再弹 s2 栈顶。

:入队 1、2、3 后出队:s1 = [1,2,3](3 在顶)→ 倒入 s2 = [3,2,1](1 在顶)→ 弹出 1 ✓——每个元素最多被搬运一次,均摊 O(1)。栈与队列本质不同,但可以用两个栈实现队列(2022 真题考点)。

出栈序列合法性判定

模拟判定法——对着目标序列,缺谁进谁,进了就弹

  1. 按入栈顺序把元素依次压栈;
  2. 每压一个就看栈顶:若正是目标序列当前要出的元素,弹出并后移目标指针(可能连弹多个);
  3. 全部压完后栈空且目标走完 → 合法;中途卡住(栈顶不是想要的且没有元素可再压)→ 非法。

:入栈 1~5,判定出栈序列 4 3 5 2 1

目标 操作 栈(底→顶)
4 压 1、2、3、4 → 弹 4 1 2 3
3 栈顶即 3 → 弹 1 2
5 压 5 → 弹 5 1 2
2 弹 2 1
1 弹 1

合法 ✓。而 4 3 5 1 2:弹完 5 后栈为 [1 2],目标要 1 但栈顶是 2 且无元素可压——非法

禁式(3 元素判非法的捷径):出栈序列中若出现“…3, 1, 2…”型(大的先出、然后是更早的两个按原序),必非法——n 个元素共 \(\dfrac{1}{n+1}\binom{2n}{n}\)(Catalan 数)种合法序列,n=4 时 14 种。

混合模拟真题演算

(2025 真题):初始空栈 S、空队列 P,顺次处理 \(A = 7,5,8,3,1,4,2\):奇数压栈;偶数且栈非空则弹栈顶入 P;偶数且栈空则跳过。

读到 奇/偶 动作 栈 S(底→顶) 队列 P
7 7
5 7 5
8 弹 5 入 P 7 5
3 7 3 5
1 7 3 1 5
4 弹 1 入 P 7 3 5 1
2 弹 3 入 P 7 5 1 3

结束:P = 5, 1, 3

练习题目

练习 1 · 栈的特性

题目

栈的存取原则是( )

  • A. 先进先出
  • B. 后进先出
  • C. 随机存取
  • D. 按下标存取
答案与解析

答案:B

只在栈顶进出,最后进的最先出(LIFO)。

练习 2 · 队列的特性

题目

队列的存取原则是( )

  • A. 后进先出
  • B. 随机存取
  • C. 先进先出
  • D. 两端都进都出
答案与解析

答案:C

队尾进、队头出,先来的先走(FIFO)——排队买票。

练习 3 · 栈顶输出

题目

依次 push 1、2、3、4 后 pop 两次,再 push 5,此时栈顶到栈底依次是( )

  • A. 5 2 1
  • B. 5 3 2
  • C. 1 2 5
  • D. 5 4 3
答案与解析

答案:A

push 后栈(底→顶)1 2 3 4;pop 两次弹掉 4、3 剩 1 2;push 5 → 栈 1 2 5,顶是 5。

练习 4 · 队列输出

题目

依次入队 a、b、c 后出队一次,再入队 d,再出队两次,出队序列是( )

  • A. c b a
  • B. a b c
  • C. b c d
  • D. a b d
答案与解析

答案:D

出队从头走:先 a;再入 d 队列 b c d;连出 b、d——共 a、b、d。

练习 5 · 312 禁式

题目

入栈顺序 1、2、3,下列不可能的出栈序列是( )

  • A. 1 2 3
  • B. 3 2 1
  • C. 3 1 2
  • D. 2 1 3
答案与解析

答案:C

要出 3 必须先压 1、2、3,此时 2 在 1 上面,弹完 3 只能先 2 后 1——3 1 2 要求 1 抢在 2 前面,矛盾。“312”型是判非法的最小模式。

练习 6 · 五元素合法序列

题目

入栈顺序 1~5,下列出栈序列合法的是( )

  • A. 4 3 5 2 1
  • B. 4 3 5 1 2
  • C. 5 4 1 2 3
  • D. 2 5 1 3 4
答案与解析

答案:A

模拟:压 1-4 弹 4、弹 3,压 5 弹 5,再依次弹 2、1 ✓。B 在弹完 5 后栈 [1 2] 目标要 1(栈顶 2)卡死;C 弹完 4 后栈 [1 2 3] 目标 1(栈顶 3)卡死;D 弹 2 后压 3 4 5 弹 5,栈 [1 3 4] 目标 1 卡死。

练习 7 · 合法序列计数

题目

4 个不同元素依次入栈,可能的出栈序列共有( )种。

  • A. \(24\)
  • B. \(10\)
  • C. \(16\)
  • D. \(14\)
答案与解析

答案:D

Catalan 数 \(C_4 = \frac{1}{5}\binom{8}{4} = 14\);全排列 24 里被禁掉 10 种。

练习 8 · 入栈即出的序列

题目

若每个元素入栈后立即出栈,n 个元素的出栈序列是( )

  • A. 与入栈顺序相同
  • B. 与入栈顺序相反
  • C. 任意
  • D. 无法确定
答案与解析

答案:A

进一个弹一个,栈只是“过一手”,顺序不变;全部压完再弹(B)才得到逆序。

练习 9 · 逆序输出

题目

依次压入 a、b、c、d 后全部弹出,输出顺序是( )

  • A. d c b a
  • B. a b c d
  • C. a d b c
  • D. 不确定
答案与解析

答案:A

一口气压完再弹 = 完全逆序——栈天然“倒序输出”。

练习 10 · top 指针

题目

数组栈 stk[]top 指向栈顶元素且空栈 top=0,push x 的操作是( )

  • A. stk[top++] = x;
  • B. stk[++top] = x;
  • C. stk[top] = x; top--;
  • D. top++; stk[top-1] = x;
答案与解析

答案:B

top=0 表示空(不存元素),先 ++ 到 1 再存。A 会把元素存进 stk[0] 且空栈语义被破坏——两套约定(top 指向顶 / 指向下一空位)别混用。

练习 11 · 循环队列下标

题目

容量 8 的循环队列,rear = 7 时再入队一个元素后 rear =( )

  • A. \(8\)
  • B. \(7\)
  • C. \(0\)
  • D. \(1\)
答案与解析

答案:C

\((7 + 1) \bmod 8 = 0\)——下标绕回开头,这就是“循环”。

练习 12 · 牺牲一格判满

题目

容量 8 的数组实现循环队列(牺牲一格法),最多同时存( )个元素;判满条件是( )

  • A. \(8\)rear == head
  • B. \(8\)(rear+1)%8 == head
  • C. \(7\)(rear+1)%8 == head
  • D. \(7\)rear == head
答案与解析

答案:C

留一格空区分“满”和“空”:两者都 head == rear 就分不清了。想存满 8 个要额外维护计数变量。

练习 13 · 队列元素个数

题目

循环队列容量 N,head=2、rear=7(rear 指向下一空位),元素个数是( )

  • A. \(7\)
  • B. \(4\)
  • C. \(9\)
  • D. \(5\)
答案与解析

答案:D

\((rear - head) \bmod N = 5\)(未绕圈时就是差值;绕圈时加 N 再模)。

练习 14 · STL 接口

题目

stack<int> s 已有元素,取栈顶并删除,正确写法( )

  • A. int x = s.pop();
  • B. int x = s.top(); s.pop();
  • C. s.pop(x);
  • D. int x = s.front(); s.pop();
答案与解析

答案:B

pop() 不返回值,先 top()pop()front() 是队列的接口。

练习 15 · 队列接口

题目

queue<int> q 的队头元素用( )读取。

  • A. q.top()
  • B. q.back()
  • C. q.front()
  • D. q[0]
答案与解析

答案:C

队列 front/back;top 是栈的——接口混用是最常见的手误。

练习 16 · 双栈实现队列的原理

题目

用两个栈 s1、s2 模拟队列,出队时( )

  • A. 直接弹 s1 栈顶
  • B. 做不到
  • C. 交替弹 s1、s2
  • D. s2 为空时把 s1 全部倒入 s2,再弹 s2 栈顶
答案与解析

答案:D

倒一次顺序:s1 里的“后进先出”经 s2 再反一次变成“先进先出”。倒空后再倒新的一批,每个元素至多搬一次。

练习 17 · 双栈队列追踪

题目

依次执行:入队 1、2、3,出队一次,入队 4,出队一次。出队的两个元素是( )

  • A. 1 2
  • B. 3 4
  • C. 1 4
  • D. 2 3
答案与解析

答案:A

第一次出队:s1=[1,2,3] 倒入 s2=[3,2,1],弹 1;入队 4 压 s1=[4];第二次出队:s2 非空直接弹 2。队列序 1、2 ✓。

练习 18 · 栈与 BFS/DFS

题目

深度优先搜索(DFS)与广度优先搜索(BFS)分别借助( )

  • A. 队列、栈
  • B. 栈、队列
  • C. 都用队列
  • D. 都用栈
答案与解析

答案:B

DFS 一条路走到黑(回溯 = 弹栈),BFS 一层层扩(先来先服务 = 队列)。

练习 19 · 中缀转后缀用栈

题目

表达式求值 / 中缀转后缀算法中,栈用来存( )

  • A. 操作数
  • B. 运算符(比较优先级决定弹栈)
  • C. 括号对
  • D. 结果
答案与解析

答案:B

操作数直接输出,运算符进栈等优先级裁决(详见表达式页)。

练习 20 · 队列空判定

题目

顺序队列(非循环)只从队尾加、队头删,head > rear(rear 指向下一空位)说明( )

  • A. 队满
  • B. 下标错误
  • C. 有一个元素
  • D. 队空
答案与解析

答案:D

rear 追着 head 走,追过头(相等或超过)即空。

练习 21 · 双端队列

题目

deque(双端队列)的特点是( )

  • A. 两端都能进能出
  • B. 只能一端进出
  • C. 先进后出
  • D. 自动排序
答案与解析

答案:A

两端开放;栈和队列都是它的特例(只用一端 / 一端进一端出)。

练习 22 · 混合模拟(自编)

题目

空栈,顺次处理序列 3, 1, 4, 1, 5:奇数压栈、偶数则弹栈顶(若有)。处理完后栈(底→顶)为( )

  • A. 3 1 1 5
  • B. 3 1 5
  • C. 3 1
  • D. 5 1 3
答案与解析

答案:B

3 压、1 压、4 偶弹 1(剩 3)、1 压(3 1)、5 压(3 1 5)。

练习 23 · 混合模拟(队列入队)

题目

空队列,顺次执行:入 1、入 2、出、入 3、出、入 4。最终队列(头→尾)是( )

  • A. 1 2 3 4
  • B. 3 4
  • C. 4 3 2
  • D. 2 3 4
答案与解析

答案:D

出队两次走的是 1、2;剩 3、4 在队里(头 3 尾 4)。

练习 24 · 出栈序列数对照

题目

3 个元素入栈,合法出栈序列有( )种。

  • A. \(5\)
  • B. \(6\)
  • C. \(4\)
  • D. \(3\)
答案与解析

答案:A

Catalan \(C_3 = 5\):全排列 6 种里只有 3 1 2 非法。

练习 25 · 卡住的时刻

题目

入栈顺序 a~e,模拟出栈序列 c, d, a, ... 时,弹出 d 之后(栈内 a、b)目标要 a——此时( )

  • A. 弹 b 再弹 a,序列改为合法
  • B. 已无元素可压而栈顶 b ≠ a,序列非法
  • C. 把 b 弹掉扔了再弹 a
  • D. 重头再压一遍
答案与解析

答案:B

判定法的“卡住”:想要的元素被压在下面、又没有新元素可入,只能判非法——这是 2021 真题 c,d,a,e,b 非法的确切原因。

练习 26 · 输出受限辨析

题目

n 个元素依次入栈且允许随时出栈,出栈序列中第一个元素( )

  • A. 一定是 1
  • B. 可以是任意一个
  • C. 只能是 1 或 n
  • D. 一定是 n
答案与解析

答案:B

想让第 k 个先出:压 k 个、立即弹第 k 个——谁都能当第一个;受限的是后续(被压住的按序受限)。

历年真题

2021 年 · 第 5 题

题目

对于入栈顺序为 a, b, c, d, e 的序列,下列( )不是合法的出栈序列。

  • A. a, b, c, d, e
  • B. e, d, c, b, a
  • C. b, a, c, d, e
  • D. c, d, a, e, b
答案与解析

答案:D

模拟 D:压 a b c 弹 c,压 d 弹 d(此时栈 [a b]),目标下一个是 a——栈顶是 b 且 e 还没压。若压 e 再弹 e 得 c d e ...,顺序不符;不压则 a 被 b 压着。卡住,非法

A(进一个弹一个)、B(全压完倒出)、C(压两个弹两个再进出)均合法。

2022 年 · 第 2 题

题目

\(6\) 个元素,按照 \(6\)\(5\)\(4\)\(3\)\(2\)\(1\) 的顺序进入栈 S,请问下列哪个出栈序列是非法的( )。

  • A. 5 4 3 6 1 2
  • B. 4 5 3 1 2 6
  • C. 3 4 6 5 2 1
  • D. 2 3 4 1 5 6
答案与解析

答案:C

模拟 C:依次压 6 5 4 3,弹 3;目标 4,栈顶正是 4,弹;目标 6,栈顶是 5——压 2、1 后栈 [6 5 2 1],栈顶 1 ≠ 6,卡住非法(6 被 5 压着,而 5 又被 2、1 压着,救不出来)。

2022 年 · 第 5 题

题目

假设栈 S 和队列 Q 的初始状态为空。存在 e1~e6 六个互不相同的数据,每个数据按照进栈 S、出栈 S、进队列 Q、出队列 Q 的顺序操作,不同数据间的操作可能会交错。已知栈 S 中依次有数据 e1e2e3e4e5e6 进栈,队列 Q 依次有数据 e2e4e3e6e5e1 出队列。则栈 S 的容量至少是( )个数据。

  • A. \(2\)
  • B. \(3\)
  • C. \(4\)
  • D. \(6\)
答案与解析

答案:B

出队序 = 出栈序,模拟“压入 e1~e6、能出就出”:

事件 栈内(底→顶) 说明
压 e1、e2 → 出 e2 e1 栈存 1
压 e3、e4 → 出 e4、e3 e1 峰值 3(e1,e3,e4 同存)
压 e5、e6 → 出 e6、e5 e1 峰值 3
出 e1

栈最多同时存 3 个 → 容量至少 3。

2022 年 · 第 10 题

题目

以下对数据结构的表述不恰当的一项为:( )。

  • A. 图的深度优先遍历算法常使用的数据结构为栈。
  • B. 栈的访问原则为后进先出,队列的访问原则是先进先出。
  • C. 队列常常被用于广度优先搜索算法。
  • D. 栈与队列存在本质不同,无法用栈实现队列。
答案与解析

答案:D

两个栈串联即可模拟队列(倒一次序);A/B/C 都是标准表述。

2024 年 · 第 13 题

题目

给定一个空栈,支持入栈和出栈操作。若入栈操作的元素依次是 1 2 3 4 5 6,其中 1 最先入栈、6 最后入栈,下面哪种出栈顺序是不可能的?( )

  • A. 6 5 4 3 2 1
  • B. 1 6 5 4 3 2
  • C. 2 4 6 5 3 1
  • D. 1 3 5 2 4 6
答案与解析

答案:D

模拟 D:弹 1(进出即弹);压 2 3 弹 3;压 4 5 弹 5——目标 2,栈 [2 4],栈顶 4 ≠ 2,卡住(压 6 也没用)→ 非法。A 全倒序、B 弹 1 后全压再倒、C 逐段“压两个弹一个”都合法。

2025 年 · 第 15 题

题目

给定一个初始为空的整数栈 \(S\) 和一个空的队列 \(P\)。我们按顺序处理输入的整数队列 \(A: 7, 5, 8, 3, 1, 4, 2\)。对于队列 \(A\) 中的每一个数,执行以下规则:如果该数是奇数,则将其压入栈 \(S\);如果该数是偶数,且栈 \(S\) 非空,则弹出一个栈顶元素,并加入到队列 \(P\) 的末尾;如果该数是偶数,且栈 \(S\) 为空,则不进行任何操作。当队列 \(A\) 中的所有数都处理完毕后,队列 \(P\) 的内容是什么?( )

  • A. 5, 1, 3
  • B. 3, 1, 5
  • C. 7, 5, 3
  • D. 5, 1, 3, 7
答案与解析

答案:A

完整逐元素演算见上文“混合模拟真题演算”的七行表格:三次偶数各弹一次栈顶(5、1、3),7 留在栈底永不出。

易错小结

  • 栈 LIFO 只碰栈顶;队列 FIFO 尾进头出;STL 的 top()(栈)/front()(队列)别混,pop() 不返回值;
  • 出栈序列判定:缺谁进谁、进了就弹,卡住即非法(2019~2024 反复考);n 元素合法序列 = Catalan 数;
  • “312”型是最小非法模式:大者先出后,更早的两个必须逆序出;
  • 循环队列取模绕圈;牺牲一格判满 (rear+1)%N == head,判空 head == rear
  • 两个栈可模拟队列(s2 空时整体倒 s1);DFS 用栈、BFS 用队列;
  • 混合模拟题列表格逐行走,别跳步。