栈这种数据结构的特点是( )。
考点:后进先出 LIFO(A1)。
(A1)考点:栈是后进先出(LIFO, Last In First Out)的线性结构——最后进栈的元素最先出栈。
解析:像一摞盘子,只能从顶端放取;先放进去的盘子被压在最下面,最后才能取出。
排除法:选"先进先出"的人那是队列(FIFO);选"随机存取"的人那是数组;选"按关键字大小存取"的人那是搜索结构。
栈中允许插入和删除的一端称为( )。
考点:栈顶与栈底(A2)。
(A2)考点:栈中允许插入和删除的一端是栈顶,另一端(固定不动)是栈底。
解析:所有操作(压入 push、弹出 pop、取顶 top)都只发生在栈顶。
排除法:选"栈底"的人栈底是封死的;选"中间元素"的人栈不能从中间操作;选"任意位置"的人栈是操作受限的结构。
栈 S 依次执行:push(1)、push(2)、push(3)、pop()、push(4)。此时栈中从栈底到栈顶的元素是( )。
考点:入栈与出栈操作(A3)。
(A3)考点:逐操作模拟——push1、push2、push3 后栈为 1 2 3(顶是 3);pop 弹走 3;push4 后栈为 1 2 4(顶是 4)。
解析:每一步只动栈顶:1 2 3 → 弹出 3 → 1 2 → 压入 4 → 1 2 4。
排除法:选 1 2 3 4 的人忘了 pop 弹走了 3;选 2 3 4 的人误以为底部的 1 也被弹出;选 1 3 4 的人 pop 没删干净。
阅读下面的程序(top 指向栈顶元素):
01int st[100], top = -1; 02st[++top] = 1; 03st[++top] = 2; 04cout << st[top]; 05cout << st[top];
程序的输出是( )。
考点:取栈顶不弹出(A4)。
(A4)考点:读栈顶(st[top])不改变栈——连续两次读,读到的都是同一个元素。
解析:st[top] 只是访问,没有 top--,两次输出都是栈顶的 2,即 22。
排除法:选 21 的人以为读取也会弹出;选 12 的人以为读到的是栈底;选"只输出一次 2"的人 cout 执行两次就输出两次。
数组实现的栈用 top = -1 表示栈空。pop 操作前应检查的条件是( )。
考点:栈空判断(A5)。
(A5)考点:top = -1 表示栈空——pop 前应检查 top == -1,空栈弹出是未定义行为。
解析:top 从 -1 起,压一个变 0;top 回到 -1 就说明没有元素了。
排除法:选 top == 0 的人忘了 -1 初始化时 0 表示有 1 个元素;选 top > 0 的人条件写反(这是非空);选 top < 100 的人那是判栈满的上界检查。
某数据结构依次执行「压入 A、压入 B、弹出 B、压入 C」后,容器内从底到顶为 A、C。该数据结构是( )。
考点:结构图示识别(A6)。
(A6)考点:从操作序列反推结构——压 A、压 B、弹出 B、压 C:后进 B 先出且从同一端操作 = 栈。真题 2020 年考过图示题。
解析:队列弹出的是最先进的 A(不是 B);二叉搜索树和哈希表的插入取出都不是这种"压入/弹出"模型。
排除法:选"队列"的人队列应弹出 A;选"二叉搜索树"的人它按值组织而非按进入顺序;选"哈希表"的人它是按关键字存取。
入栈顺序为 a, b, c, d, e,下列可能的出栈序列是( )。
考点:合法出栈序列判定(B1)。
(B1)考点:入栈序 a~e,判定哪个出栈序列可能——用模拟法。真题 2021 年原题。
解析:b a e d c:a、b 入栈即弹 b、弹 a;c、d、e 全入,依次弹 e、d、c ✓ 合法。
排除法:选 a c e b d 的人:e 出栈后栈内 c 之下是 b、d 之下压着……模拟到目标 b 时 d 挡在 b 上面,非法;选 c d a b e 的人:d 出后目标 a 被 b 挡住,非法;选 a e d b c 的人:e、d 出后目标 b 被 c 挡住,非法。
入栈顺序为 1, 2, 3, 4,若 4 个元素全部入栈后再依次出栈,出栈序列是( )。
考点:全部入完再出的序列(B2)。
(B2)考点:全部入栈后再出 = 完整逆序:4 3 2 1。
解析:栈把顺序完全颠倒——这是栈"逆序"能力的极端情况。
排除法:选 1 4 3 2 的人部分元素提前出了;选 1 2 3 4 的人那是队列;选 2 1 4 3 的人那是分段逆序(没全入完就出)。
入栈顺序为 1, 2, 3,若每个元素入栈后立即出栈(进一个出一个),出栈序列是( )。
考点:边进边出的模拟(B3)。
(B3)考点:每个元素入栈后立即出栈 = 顺序保持 1 2 3。
解析:进一个出一个,元素不在栈中停留,顺序不变——这是栈"保序"的极端情况。
排除法:选 3 2 1 的人那是全部入完再出;选 2 1 3 和 1 3 2 的人混入了停留。
6 个元素按 6, 5, 4, 3, 2, 1 的顺序进栈,下列非法的出栈序列是( )。
考点:非法序列识别(B4)。
(B4)考点:入栈序 6,5,4,3,2,1 找非法出栈序列。真题 2022 年原题。
解析:3 4 6 5 2 1:要 3 先出需压入 6,5,4,3;弹 3、弹 4 后目标是 6,但栈顶是 5——5 挡在 6 前面,非法。
排除法:选 5 4 3 6 2 1 的人:压 6,5,4,3 弹 5、4、3,弹 6,再压 2、1 依次弹——合法;选 6 5 4 3 2 1 的人:即入即出全逆序,合法;选 2 3 4 1 5 6 的人:压到 2 弹 2、弹 3、弹 4,压 1 弹 1,弹 5、弹 6——合法。
3 个不同元素依次进栈(可随时出栈),可能的出栈序列共有( )种。
考点:出栈序列计数(B5)。
(B5)考点: 个元素的出栈序列数是卡特兰数 (不要求记公式, 时枚举): 种。
解析:枚举 3 个元素的全部 个排列,模拟器验证只有 1 3 2 之外还有一种非法……实际合法的是 123、132、213、231、321 共 5 种,仅 312 非法。
排除法:选 、 的人都漏了某些合法序列;选 的人以为全排列都行(312 非法:3 出栈后 1 被 2 挡住)。
入栈顺序 1, 2, 3, 4(按此顺序依次到达)。关于出栈序列,下列说法正确的是( )。
考点:单调入栈的灵活性(B6)。
(B6)考点:出栈序列不是全部排列都行——如 4 1 2 3:4 出栈后 1 在 2、3 下面,不可能先出。
解析:栈允许"进一半就出",因此部分排列可能;但大数先出后,被压住的小数顺序无法重排。
排除法:选"只有 4 3 2 1"的人忘了可以边进边出;选"只有 1 2 3 4"的人同样片面;选 种的人 都不止,且并非全可能。
判断一个出栈序列是否合法的实用方法是( )。
考点:出栈序列判定方法(B7)。
(B7)考点:判定出栈序列合法性的标准方法 = 模拟:按入栈序逐个压栈,栈顶等于当前目标就弹出;处理完目标序列后栈空则合法。
解析:这是机械可靠的方法,适合考场上快速验证;其他"看规律"的捷径都不可靠。
排除法:选"看是否递减"的人全逆序只是特例;选"包含入栈序作为子序列"的人这个条件必要不充分;选"数后面比它小的个数"的人那是排序的判定。
入栈顺序为 1, 2, 3, 4, 5,下列不可能的出栈序列是( )。
考点:五元素序列判定(B8)。
(B8)考点:5 元素合法性模拟——4 3 5 1 2:压 1234 弹 4 弹 3;压 5 弹 5;目标 1 时栈内 1 2(2 在 1 上面),2 挡住 1,非法。
解析:模拟到"目标 1"那一步就卡住——1 之上有 2,必须先出 2,但 2 排在 1 后面,矛盾。
排除法:选 5 4 3 2 1 的人那是全进全出(合法);选 4 5 3 2 1 的人:压 1234 弹 4,压 5 弹 5,弹 3 2 1,合法;选 3 4 2 5 1 的人:压 123 弹 3,压 4 弹 4,弹 2,压 5 弹 5,弹 1,合法。
入栈顺序为 a, b, c, d, e,栈的容量为 3(同时最多存 3 个元素)。下列出栈序列中,因容量不足而不可能实现的是( )。
考点:栈容量约束(B9)。
(B9)考点:栈容量限制下的出栈序列——e d c b a 要求 a b c d e 全部同时在栈中(容量 5),容量 3 装不下。
解析:e 最先出栈意味着它入栈时 a b c d 都还压在下面——5 个同存,超过容量 3。
排除法:选 c d e b a 的人:压 a b c(满)弹 c,压 d 弹 d,压 e 弹 e,弹 b 弹 a——全程不超 3,可以实现;选 b c d e a 的人:压 a b 弹 b,压 c 弹 c,压 d 弹 d,压 e 弹 e,弹 a——容量最多 2,可行;选 a b c d e 的人即进即出,容量 1 就够。
3 个元素 e1, e2, e3 依次到达,每个元素按「进栈 S、出栈 S、进队列 Q、出队列 Q」处理,元素之间的操作可以交错。最终不同的出队列序列共有( )种。
考点:经栈过队列的序列数(B10)。
(B10)考点:出队列序列 = 出栈序列——队列保序,所以"经过栈再进队列"的序列约束完全由栈决定:3 元素 种。
解析:每个元素出 S 后进 Q,Q 的先进先出保证出 Q 顺序 = 出 S 顺序 → 可能的出 Q 序列数 = 可能的出栈序列数 = 卡特兰数 。真题 2022 年考过此模型。
排除法:选 的人以为队列强制保序就只剩原序(栈那段已打乱顺序);选 的人少算;选 的人以为全排列都行。
关于合法出栈序列的性质,下列说法正确的是( )。
考点:出栈序列的判定定理(B11)。
(B11)考点:出栈序列的必要性质——任何元素后面比它小的元素必然递减排列(它们在栈中层层叠放,只能从上往下依次弹出)。
解析:这些小元素入栈时在该元素之上,出栈时只能按叠放的反序(递减)弹出——这是快速排除非法序列的利器。
排除法:选"递增排列"的人方向反了;选"循环移位"的人那是特殊情形;选"不能连续递减三段"的人全逆序就连续递减却合法。
入栈顺序为 1, 2, 3, 4, 5, 6,下列不可能的出栈序列是( )。
考点:六元素真题判定(B12)。
(B12)考点:6 元素真题级判定——6 4 2 1 3 5:压 123456 弹 6;目标 4 时栈顶是 5,5 挡住 4,非法。真题 2024 年考过此问法。
解析:6 第一个出栈后栈内 1~5(5 在顶),后续只能按 5 4 3 2 1 的递减顺序弹出——而目标序列里 4 后面是 2 不是 5,卡住。
排除法:选 4 5 3 6 2 1 的人:压 1234 弹 4,压 5 弹 5,弹 3,压 6 弹 6,弹 2 弹 1,合法;选 1 3 5 6 4 2 的人逐段模拟合法;选 2 4 3 6 5 1 的人模拟合法。
4 个不同元素依次进栈(可随时出栈),可能的出栈序列共有( )种。
考点:四元素序列计数(B13)。
(B13)考点: 元素出栈序列数 = 卡特兰数—— 种。
解析:枚举验证: 个排列中模拟器判定 14 个合法。公式 (了解即可,考场上小规模枚举更稳)。
排除法:选 的人以为是 ;选 的人以为全排列都行(4 1 2 3 等 10 个非法);选 的人数漏。
入栈顺序为 a, b, c, d。若 a 是第一个出栈的元素,满足条件的出栈序列共有( )种。
考点:首元素固定后的计数(B14)。
(B14)考点:a 第一个出栈 = a 进栈即出,剩下 b c d 的栈操作独立进行——卡特兰数 种。
解析:a 弹出后栈空,b c d 构成全新的 3 元素栈问题:5 种。
排除法:选 的人没固定首元素;选 或 的人数错 3 元素的情形。
表达式 a*(b+c)*d 的后缀表达式是( )。
考点:中缀转后缀(C1)。
(C1)考点:a*(b+c)*d 的后缀 = 按运算顺序排列:先 b+c,再乘 a,再乘 d:a b c + * d *。真题 2021 年原题。
解析:括号优先 → b c +;a * (...) → a b c + *;再乘 d → a b c + * d *。
排除法:选 a b c + d * * 的人运算顺序排错(d 先跟括号结果乘了);选 a b + c * d * 的人括号加错了对象;选 a * b c + * d 的人后缀里不允许运算符夹在操作数中间。
后缀表达式 6 2 3 + - 3 8 2 / + * 对应的中缀表达式是( )。
考点:后缀转中缀(C2)。
(C2)考点:后缀 6 2 3 + - 3 8 2 / + * 逐栈还原。真题 2023 年原题。
解析:2 3 +→(2+3);6 - → (6-(2+3));8 2 /→(8/2);3 +→(3+(8/2));* → (6-(2+3))*(3+(8/2)),值为 。
排除法:选 6 - 2 + 3 * 3 + 8 / 2 的人丢了括号(运算顺序错);选 6 - (2 + 3) * (3 + 8 / 2) 的人减法的作用域错(那是 );选 (6 - 2 + 3) * (3 + 8) / 2 的人分组全错。
表达式 a+(b-c)*d 的前缀表达式是( )。
考点:中缀转前缀(C3)。
(C3)考点:a+(b-c)*d 的前缀 = 运算符放前面:+ a * - b c d。真题 2022 年原题。
解析:最后计算的 + 在最前;* 次之;(b-c) 的 - 在它两个操作数前。
排除法:选 a + b - c * d 的人那是中缀本身;选 a b c - d * + 的人那是后缀;选 + * a - b c d 的人 * 的操作数错位(a 乘的应该是 (b-c) 整体)。
后缀表达式 3 4 + 2 * 的值是( )。
考点:后缀表达式求值(C4)。
(C4)考点:后缀求值用栈:遇数压栈、遇运算符弹两个算——3 4 + 2 * = 。
解析:压 3、压 4;+ 弹 4、3 算 7 压回;压 2;* 弹 2、7 算 14。
排除法:选 的人先算了 ;选 的人运算顺序错;选 的人把 + 和 * 混了。
前缀表达式 * + 3 4 2 的值是( )。
考点:前缀表达式求值(C5)。
(C5)考点:前缀 * + 3 4 2 从右往左扫(或递归):先算 + 3 4 = 7,再 * 7 2 = 14。
解析:前缀求值从右端开始:压 2、压 4、压 3;遇 + 弹 3、4 得 7 压回;遇 * 弹 7、2 得 14。
排除法:选 的人先算了 ;选 的人把两个运算符的作用域弄混;选 的人运算对象错位。
后缀表达式(逆波兰式)的最大优点是( )。
考点:后缀表示的意义(C6)。
(C6)考点:后缀的核心优点 = 按运算顺序直接排列,无需括号和优先级。
解析:运算符出现的位置就是运算发生的时机,机器(栈)从左到右扫一遍即可计算。
排除法:选"不需要知道运算符优先级就能算——因为它按运算顺序直接排列"的人描述冗长且因果绕;选"人人易读"的人后缀恰恰难读;选"书写最短"的人不一定更短。
中缀表达式 (a+b)*c 转成后缀时,括号( )。
考点:括号在后缀中的去向(C7)。
(C7)考点:中缀转后缀时括号消失——运算顺序已体现在排列顺序中。
解析:括号的作用(强制优先)被"运算符后置的顺序"替代。
排除法:选"保留为特殊符号"的人后缀中没有括号;选"转换为优先级标记"的人没有这种机制;选"转移到运算符前"的人那是前缀的运算符位置,不是括号。
后缀表达式 a b c + * 对应的前缀表达式是( )。
考点:后缀转前缀(C8)。
(C8)考点:后缀 a b c + * = ,前缀把运算符前置:* a + b c。
解析:先还原成中缀 的结构(心里过一遍),再按"运算符在操作数前"改写:最外层 * 最前,+ 在它两个操作数前。
排除法:选 * + a b c 的人把 + 的作用域错位(+ 应该只管 b 和 c);选 a b c + * 的人没有转换(还是后缀);选 + a * b c 的人最外层运算符认错(乘法才是最后算的)。
用运算符栈把中缀 a + b * c 转后缀,读到 * 时(a、+、b 已处理),运算符栈从底到顶是( )。
考点:中转后缀的栈算法状态(C9)。
(C9)考点:shunting-yard 过程状态——a + b * c 读到 * 时:+ 在栈中,* 优先级高于 + 不弹、直接入栈:栈为 + *。
解析:高优先级入栈(压住低的)、低优先级入栈前先弹走不低于它的——两条规则决定栈的每一步形态。
排除法:选 * + 的人栈序反了(* 在 + 上面);选"空"的人以为遇运算符就清栈;选 + 的人忘了 * 也入栈。
双栈法求中缀表达式的值时,读到新运算符,若其优先级高于栈顶运算符,正确的做法是( )。
考点:双栈求值的弹栈规则(C10)。
(C10)考点:新运算符优先级高于栈顶 → 直接入栈(优先级低的先算的规则由"不低于才弹"保证)。
解析:弹栈条件是"栈顶优先级 ≥ 新运算符";严格高于时入栈等待,后面遇到更低或结尾时再统一算。
排除法:选"先弹再入"的人那是优先级不高于时的动作;选"全部弹出"的人那是遇括号结束时的动作;选"丢弃"的人运算符不能丢。
把中缀表达式 (a+b)*c 画成一棵表达式树(操作数在叶、运算符在内点),对该树做后序遍历得到的是( )。
考点:表达式树与遍历(C11)。
(C11)考点:表达式树的三种遍历对应三种表达式——后序遍历 = 后缀表达式(左右根 = 操作数操作数运算符)。
解析:中序(左根右)得到中缀;前序(根左右)得到前缀;后序(左右根)得到后缀——表达式转换的另一种理解方式。
排除法:选"前缀表达式"的人那是先根遍历;选"中缀表达式"的人那是中序遍历;选"括号表达式"的人没有这种标准名称。
表达式 a+b*c-(d/e+f)*g 的后缀表达式是( )。
考点:复杂中缀转后缀(C12)。
(C12)考点:多运算符混合转换——a+b*c-(d/e+f)*g:括号内先转 d e / f +,乘 g 得 d e / f + g *,整体相减:a b c * + d e / f + g * -。
解析:按优先级分层拆: → a b c * +; → d e / f + g *;两者相减拼接。
排除法:选 a b c * + d e / f + * - 的人把 g 乘进了括号内部;选 a b + c * d e / f + g * - 的人丢了 b*c 的优先级;选 a b c * + d e f + / * g - 的人除法作用域错。
前缀表达式 * + a b - c d 对应的中缀表达式是( )。
考点:前缀转中缀(C13)。
(C13)考点:前缀还原中缀——* + a b - c d:+ a b = (a+b),- c d = (c-d),* 连接两者:。
解析:前缀从右往左扫,遇到运算符取它后面两个已还原的式子拼接并加括号。
排除法:选 a + b * c - d 的人丢了括号(运算顺序变);选 (a + b) * c - d 的人把 (c-d) 拆散了;选 (a - b) * (c + d) 的人两个运算符都认错。
后缀表达式 7 2 3 * - 的值是( )。
考点:含除法的后缀求值(C14)。
(C14)考点:后缀 7 2 3 * -:先算 ,再 ——注意弹栈顺序(先弹的是右操作数)。
解析:压 7、2、3;* 弹 3、2 得 6 压回;- 弹 6、7 得 。
排除法:选 的人算成了 (把减号当加号);选 的人操作数顺序反了();选 的人运算对象错位。
前缀表达式又称( ),后缀表达式又称( )。
考点:波兰式与逆波兰式(C15)。
(C15)考点:命名约定——前缀 = 波兰式(波兰数学家发明),后缀 = 逆波兰式。
解析:两者同源:把运算符放操作数前叫波兰式,放后面叫逆波兰式。
排除法:选"逆波兰式、波兰式"的人前后对调;其余两组搭配无此说法。
队列的特点是( )。
考点:先进先出 FIFO(D1)。
(D1)考点:队列是先进先出(FIFO)——先入队的先出队,像排队买票。
解析:入队在队尾、出队在队头,顺序保持不变。
排除法:选"后进先出"的人那是栈;选"两端都可进出且等价"的人那是双端队列;选"按值大小有序"的人队列无序。
队列中允许删除的一端是( ),允许插入的一端是( )。
考点:队头与队尾(D2)。
(D2)考点:队列队头出、队尾进——删除在队头、插入在队尾。
解析:队头(front)是最早进入、即将出队的元素;队尾(rear)是新元素插入的位置。
排除法:选"队尾、队头"的人方向反了;选"两端都行"的人那是双端队列;选"中间、队尾"的人队列不能从中间操作。
空队列依次执行 push(1)、push(2)、push(3)、pop()、push(4) 后(push 表示入队),从队头到队尾的元素是( )。
考点:入队与出队(D3)。
(D3)考点:队列 FIFO 模拟——入 1、2、3 后出队的是 1;再入 4:队列 2 3 4。
解析:1 2 3 → 出 1 → 2 3 → 入 4 → 2 3 4。
排除法:选 1 2 3 4 的人忘了出队;选 4 3 2 的人方向全反;选 1 3 4 的人出队出错了元素。
元素 1, 2, 3 依次入队(只入队出队,无其他操作),出队序列是( )。
考点:队列输出序列唯一性(D4)。
(D4)考点:只入队出队(无中途插队)时,队列的出队序列 = 入队序列 1 2 3——唯一。
解析:FIFO 保序,这也是栈与队列的本质区别(栈可以边进边出改变顺序,队列不能)。
排除法:选 3 2 1 的人那是栈的全逆序;选"取决于实现"的人与实现无关,由结构性质决定;选 2 1 3 的人队列无法重排。
容量为 的循环队列(数组下标 ),rear = 4 时再入队一个元素,新的 rear 是( )。
考点:循环队列取模(D5)。
(D5)考点:循环队列下标取模回绕——容量 5、rear=4 时入队后 rear = (4+1) % 5 = 0。
解析:数组末尾绕回头部,这就是"循环"的含义。
排除法:选 的人加错方向;选 的人忘了移动;选 的人越界(下标只有 0~4)。
容量为 的循环队列用 (rear + 1) % n == front 判满时,实际最多能存( )个元素。
考点:循环队列判满(D6)。
(D6)考点:(rear + 1) % n == front 判满时牺牲一格区分满与空——实际容量 。
解析:若不牺牲一格,满和空时都是 front == rear,无法区分。
排除法:选 的人忘了牺牲的那格;选 的人容量不会超过数组大小;选 的人概念错。
容量为 的循环队列(下标 ),当前 front = 2、rear = 5。执行 2 次出队、3 次入队后,front 和 rear 分别是( )。
考点:下标综合计算(D7)。
(D7)考点:循环队列双向推进——出队 2 次 front = (2+2)%8 = 4;入队 3 次 rear = (5+3)%8 = 0(回绕)。
解析:各自独立推进取模,front 只随出队、rear 只随入队。
排除法:选"rear = 8"的人忘了取模(越界);选"rear = 1"的人多移了一位;选"front = 5"的人 front 跟着入队动了。
循环队列判空可以用 front == rear,也可以用一个 size 计数器。前一种方案的特点是( )。
考点:两种判空方案(D8)。
(D8)考点:front == rear 判空的代价——少维护一个 size 变量,但必须牺牲一个存储单元区分满与空;用 size 计数则不用牺牲。
解析:两种方案取舍:省变量 vs 省空间——考题常考"为什么留一个空位"。
排除法:选"不用牺牲存储单元"的人恰恰要牺牲;选"判满判空写法相同"的人两条件不同;选"只适用于链式存储"的人顺序存储的循环队列正是主战场。
个人编号 围成一圈,从 号开始报数,报到 的人出圈,用队列模拟。出圈的顺序是( )。
考点:约瑟夫队列模拟(D9)。
(D9)考点:约瑟夫问题的队列解法——报数 m 出圈:把队头出队、若未数到 m 再入队尾。n=5、m=3 出圈顺序 3 1 5 2 4。
解析:队 12345:数 3 出 3 → 队 4512:数 3 出 1 → 队 245:数 3 出 5 → 队 24:数 3 出 2 → 剩 4。出圈序 3 1 5 2 4。
排除法:选 3 1 5 4 2 的人最后两人处理错;选 3 5 1 2 4 的人第二轮就错;选 1 4 2 5 3 的人把"数到 3"错成"编号 3 的倍数"。
广度优先搜索(BFS)逐层扩展节点时使用队列而不是栈,原因是( )。
考点:BFS 用队列的原因(D10)。
(D10)考点:BFS 逐层扩展需要"先发现的先扩展"——队列先进先出保证层次顺序。
解析:第 k 层节点全部处理完才轮到第 k+1 层;换成栈就变成 DFS 的深入模式。
排除法:选"内存小/出队快"的人与数据结构特性无关;选"栈无法存储编号"的人栈当然能存。
双端队列(deque)与普通队列的区别是( )。
考点:双端队列(D11)。
(D11)考点:双端队列(deque)= 两端都可以插入和删除的线性结构。
解析:它同时具备栈和队列的能力(一端操作即栈、两端配合即队列);STL 的 deque 是 stack/queue 的默认底层容器。
排除法:选"只能从队尾插入"的人那是普通队列的一半;选"中间也可以插入"的人那是顺序表;选"没有区别"的人区别正是两端可操作。
输入序列 1, 2, 3, 4, 5,全部进入容器后再全部取出:经过栈的输出是( ),经过队列的输出是( )。
考点:栈与队列输出对比(D12)。
(D12)考点:同一输入全进全出——栈逆转序 5 4 3 2 1、队列保持序 1 2 3 4 5。
解析:这是两种结构最直观的分水岭实验。
排除法:选"栈 12345 队 54321"的人方向全反;选"两者相同"的人无视了结构差异。
阅读下面的程序:
01int q[100], front = 0, rear = 0; 02while (front != rear) { 03 cout << q[front] << " "; 04 front = (front + 1) % 100; 05}
若循环队列当前为空,该循环的执行情况是( )。
考点:判空代码(D13)。
(D13)考点:while (front != rear) 在空队列时——front == rear 立即成立,循环体一次也不执行。
解析:这正是"用循环条件隐式判空"的写法,安全且常用。
排除法:选"死循环"的人条件写反才死循环;选"输出垃圾值"的人没进循环体就不会输出;选"输出 100 个 0"的人同样没进循环。
栈和队列的共同点是( )。
考点:LIFO 与 FIFO 对比(E1)。
(E1)考点:栈和队列的共同点 = 都是操作受限的线性结构(插入删除只在特定端)。
解析:线性结构 + 操作受限是它们的共性;区别在受限的方式(一端 vs 两端各司其职)。
排除法:选"都只能在一端操作"的人队列两端都操作(头出尾进);选"出入顺序相同"的人恰好相反;选"都必须用数组实现"的人都能用链表实现。
「编辑器的撤销操作」和「打印任务排队」分别适合用( )实现。
考点:撤销与排队场景(E2)。
(E2)考点:场景匹配——撤销用栈(最近操作先撤销)、排队用队列(先来先服务)。
解析:撤销恢复"上一步",正是栈顶;排队系统先到先得,正是队头。
排除法:选"队列、栈"的人配反了;选"都是栈"或"都是队列"的人各错一半。
用两个栈 S1(入)和 S2(出)模拟队列,元素 1, 2, 3 依次入 S1 后,要取出队头元素 1 的操作是( )。
考点:栈实现队列(E3)。
(E3)考点:两栈模拟队列——入队压 S1;出队时把 S1 全部倒入 S2,S2 弹出的就是原队头。
解析:倒一次栈,顺序翻转两次 = 保序;S2 非空时可继续直接弹。
排除法:选"直接从 S1 弹出"的人弹的是队尾;选"从 S1 弹出 3 个取最后一个"的人绕远且弹后状态损坏;选"无法模拟"的人两栈可以模拟队列。
用队列模拟栈的 pop 操作(栈顶出),需要( )。
考点:队列实现栈(E4)。
(E4)考点:队列模拟栈的 pop——把前 个元素出队再入队(转到后面),最后出队的那個就是栈顶。
解析:转一圈后原队尾(=栈顶)到了队头,出队即弹栈;代价 。
排除法:选"直接从队头出队"的人那是队头不是栈顶;选"从队尾出队"的人顺序队列做不到(除非双端);选"用取模定位"的人取模是循环队列的事。
栈 S 和队列 Q 初始为空。元素 e1, e2, e3, e4 依次执行「进 S、出 S、进 Q、出 Q」且各元素操作不交错。最终出 Q 的序列是( )。
考点:混合操作模拟(E5)。
(E5)考点:各元素操作不交错时(e1 完整走完四步才轮 e2),栈和队列都保序——出 Q 序列 = e1 e2 e3 e4。
解析:单独一个元素过栈再过队列,顺序不变;串行处理整体保序。真题 2022 年考的是交错版(更难,序列可变)。
排除法:选 e4 e3 e2 e1 的人以为栈会逆序整体;选 e2 e4 e1 e3 的人那是交错操作才可能;选"不确定"的人不交错时是确定的。
初始空的整数栈 S 和队列 P,依次处理输入 7, 5, 8, 3:奇数压入 S、偶数入 P。处理完后先弹出 S 的全部(从栈顶往下)再输出 P 的全部(从队头往后),得到的序列是( )。
考点:奇偶分流模拟(E6)。
(E6)考点:分流模拟——奇数 7,5,3 入栈(底→顶 7,5,3),弹栈从顶往下:3,5,7;偶数 8 入队出队:8;拼接 3 5 7 8。真题 2025 年考过此考法。
解析:栈部分倒序(顶先出)、队列部分保序,先后输出再拼接。
排除法:选 7 5 3 8 的人把栈按入序输出(忘了从顶弹);选 5 7 3 8 的人弹栈顺序错;选 8 3 5 7 的人先输出了队列部分。
下列关于数据结构的表述中,不恰当的是( )。
考点:数据结构表述辨析(E7)。
(E7)考点:找不恰当表述——栈的进出端固定(顶)、队列头出尾进,都不能任意选择。真题 2022 年考过此类。
解析:操作受限正是它们的定义特征;"任意选择端"的表述与定义矛盾。
排除法:选"栈是后进先出的线性表"的人这是正确表述;选"队列是先进先出的线性表"的人同;选"都可以用数组和链表实现"的人同。
用栈 S1(入队)和 S2(出队)模拟队列:1, 2, 3 已压入 S1,此时执行一次出队(把 S1 倒入 S2 后弹出 1)。新元素 4 此时应压入( )。
考点:两栈队列的新元素去向(E8)。
(E8)考点:两栈模拟队列的纪律——入队永远进 S1、出队永远从 S2(S2 空了才把 S1 倒过来)。
解析:新元素 4 若压进 S2 会破坏 S2 的出队顺序(4 会排在 3、2 之前弹出)——纪律保证正确性。
排除法:选"S2"的人破坏了顺序;选"两个都可以"的人只有 S1 对;选"先压 S2 再倒回"的人多此一举且顺序错。
用队列模拟栈的 pop 操作,需要把前 个元素转移,单次 pop 的时间代价是( )。
考点:队列模拟栈的代价(E9)。
(E9)考点:队列模拟栈的 pop 要转移前 个元素——单次 。
解析:push 直接入队 ,代价集中在 pop;对比两栈模拟队列(均摊 ),各有取舍。
排除法:选 的人那是 push 的代价;选 的人误算了嵌套;选 的人没有对数结构参与。
输入序列 1, 2, 3, 4, 5 经过一个栈(可随时进出)后得到输出序列。下列输出序列中无法实现的是( )。
考点:中转站判定(E10)。
(E10)考点:一个栈作中转(铁路调度模型)——4 5 3 1 2:4 出后 5 出、3 出,目标 1 被 2 挡住,无法实现。
解析:模拟到目标 1 时栈内从上往下是 2、1——必须先弹 2,但输出序列里 2 在 1 后。
排除法:选 4 5 3 2 1 的人:4、5 出后 3 2 1 依次弹出,可行;选 2 1 5 4 3 的人:2 1 出后压 345 弹 5 4 3,可行;选 1 2 3 4 5 的人即进即出,可行。
输入序列 a, b, c 经过某个容器后输出 c, b, a;同样的输入经过另一个容器输出 a, b, c。这两个容器分别是( )。
考点:同输入两种输出(E11)。
(E11)考点:逆转序容器 = 栈、保序容器 = 队列——由输出反推结构。
解析:c b a 是逆序输出(栈);a b c 是原序输出(队列)。
排除法:选"队列、栈"的人配反;选"都是栈/都是队列"的人一种结构不能既保序又逆转(不中途换操作的情况下)。
输入序列 1, 2, 3, 4,要得到输出 1 2 4 3。下列判断正确的是( )。
考点:只能栈不能队列的转换(E12)。
(E12)考点:1 2 4 3 这种"局部重排"只有栈能做——1、2 进即出,3 4 进栈后 4 先出。
解析:队列只能整体保序(1234),栈能做任意合法的"后进先出"重排——1 2 4 3 恰是栈重排的一种。
排除法:选"队列可以栈不能"的人反了;选"都能"的人队列不行;选"都不能"的人栈可以。
阅读下面的程序:
01int st[100], top = -1; 02void push(int x) { 03 st[++top] = x; 04} 05push(1); push(2); push(3); 06cout << top;
程序的输出是( )。
考点:数组栈 push(F1)。
(F1)考点:st[++top] = x 先加后存——push 3 次后 top 从 -1 变 2。
解析:每次 push,top 先自增再存入;3 个元素占据下标 0、1、2,top 指向最后一个。
排除法:选 1 的人少算一次;选 -1 的人忘了自增;选 100 的人那是数组容量。
阅读下面的程序:
01int st[100], top = 2; // 栈中已有 3 个元素 02int x = st[top--]; 03cout << x << " " << top;
程序的输出是( )。
考点:数组栈 pop(F2)。
(F2)考点:st[top--] 先取后减——取下标 2 的值,top 变 1:输出 2 1。
解析:弹出动作 = 读栈顶 + 指针下移,一次表达式完成。
排除法:选 1 2 的人输出顺序反了;选 2 2 的人忘了 top 减 1;选 2 3 的人 top 加错了方向。
阅读下面的程序:
01int q[100], head = 0, tail = 0; // tail 指向队尾下一个空位 02q[tail++] = 10; 03q[tail++] = 20; 04int x = q[head++]; 05cout << x << " " << tail - head;
程序的输出是( )。
考点:队列入队出队(F3)。
(F3)考点:tail 指向队尾下一空位——入队 q[tail++]、出队 q[head++]:输出 10 1。
解析:入 10、20 后 tail=2;出队取 q[0]=10,head=1;剩余元素数 tail - head = 1。
排除法:选 20 1 的人出队取错了元素(那是队尾);选 10 2 的人忘了自己刚出队一个;选 10 0 的人把队列算空了。
容量为 的循环队列,front = 3、rear = 7(rear 指向队尾下一空位),当前队列中的元素个数是( )。
考点:循环队列长度(F4)。
(F4)考点:循环队列元素数 = (rear - front + n) % n——。
解析:加 n 再取模避免负数(rear 绕回头部时 rear < front)。
排除法:选 的人直接取了 rear;选 的人那是容量;选 -4 的人忘了取模。
阅读下面的程序(判断括号序列是否匹配):
01bool match(string s) { 02 stack<char> st; 03 for (char c : s) { 04 if (c == '(') st.push(c); 05 else if (c == ')' && !st.empty()) st.pop(); 06 else if (c == ')') return false; 07 } 08 return st.empty(); 09}
调用 match("(()") 的返回值是( )。
考点:括号匹配代码(F5)。
(F5)考点:栈法匹配——"(()") 处理完栈里剩 1 个 (,st.empty() 为假,返回 false。
解析:左括号压栈、右括号弹栈;结束时栈非空说明有左括号没配上。
排除法:选 true 的人以为只要没碰到多余右括号就匹配(左括号剩余也是不匹配);选"死循环"的人 for 循环必终止;选"编译错误"的人代码合法。
阅读下面的程序(后缀表达式求值):
01stack<int> st; 02int a = 3, b = 4, c = 2; 03st.push(a); st.push(b); st.push(c); 04int x = st.top(); st.pop(); 05int y = st.top(); st.pop(); 06st.push(x * y); 07int z = st.top(); st.pop(); 08int w = st.top(); st.pop(); 09st.push(z + w); 10cout << st.top();
程序的输出是( )。
考点:后缀求值代码(F6)。
(F6)考点:栈模拟——压 3、4、2;弹 2、4 算 压回;栈 [3,8];弹 8、3 算 。
解析:后缀 3 4 2 * + 的求值过程:乘法先(在后面)。
排除法:选 的人把表达式当成了 3 4 + 2 *;选 的人先算了 顺序错;选 的人算错一步。
C++ STL 中,栈和队列对应的容器适配器分别是( )。
考点:STL 栈与队列(F7)。
(F7)考点:STL 中栈和队列是容器适配器:stack<int>、queue<int>。
解析:它们默认基于 deque 实现,通过适配器接口只暴露栈/队列操作。
排除法:选 vector、list 的人那是底层容器(且不是适配器本身);选 set、map 的人那是关联容器;选"stack、queue 都是基础容器"的人它们是适配器不是基础容器。
阅读下面的程序(中缀转后缀,操作数为小写字母):
01string toPost(string s) { 02 stack<char> op; string out; 03 for (char c : s) { 04 if (isalpha(c)) out += c; 05 else if (c == '(') op.push(c); 06 else if (c == ')') { 07 while (op.top() != '(') { out += op.top(); op.pop(); } 08 op.pop(); 09 } else { 10 while (!op.empty() && prio(op.top()) >= prio(c)) { 11 out += op.top(); op.pop(); 12 } 13 op.push(c); 14 } 15 } 16 while (!op.empty()) { out += op.top(); op.pop(); } 17 return out; 18}
处理运算符 c 时 while 弹栈(条件 prio(op.top()) >= prio(c))的作用是( )。
考点:中转后缀代码的弹栈条件(F8)。
(F8)考点:while (prio(op.top()) >= prio(c)) 弹栈的意义——保证栈中不低于 c 优先级的运算符先输出,维持后缀"先算的在前"。
解析:例如栈中 +、新读 *:+ 优先级低不弹(乘法先算要排后面?不——低优先级留在栈里等更晚弹出,恰好让高优先级先输出);读 - 时栈中 * 高于它先弹——每一步都在维护正确顺序。
排除法:选"没有作用可以删掉"的人删掉后顺序全错;选"保证低优先级先输出"的人方向反了;选"只在遇括号时才执行"的人普通运算符间也会执行。
阅读下面的完整程序(把后缀表达式转换成中缀表达式):
01#include <iostream> 02#include <stack> 03#include <string> 04using namespace std; 05 06int main() { 07 string post = "xy+z*"; // 后缀表达式,操作数为字母 08 stack<string> st; 09 for (char c : post) { 10 if (c == '+' || c == '*') { 11 string b = st.top(); st.pop(); // 先弹出 12 string a = st.top(); st.pop(); // 后弹出 13 st.push("(" + a + c + b + ")"); 14 } else { 15 st.push(string(1, c)); 16 } 17 } 18 cout << st.top(); 19 return 0; 20}
程序运行到处理字符 * 的那一刻,变量 b 和 a 的值分别是( )。
考点:后缀转中缀的代码(F9)。
(F9)考点:后缀转中缀的完整实现——栈存子表达式串:操作数入栈;遇运算符先弹右操作数 b、再弹左操作数 a,拼成 "(" + a + c + b + ")" 压回。程序处理 xy+z* 到 * 时:x、y 已被 + 合并成 (x+y),z 刚入栈——所以 b = "z"(栈顶)、a = "(x+y)"。
解析:逐步跟踪栈:x → x y → + 弹出 y、x 压回 (x+y) → (x+y) z → * 弹出 z、(x+y) 压回 ((x+y)*z)——最终输出 ((x+y)*z)。
排除法:选 b = "(x+y)"、a = "z" 的人弹出顺序反了(先弹的 b 是栈顶 z);选 b = "y"、a = "x" 的人没意识到 x、y 已在处理 + 时合并弹出;选 b = "x"、a = "y" 的人同样没跟踪合并且顺序也错。
阅读下面的程序(双栈求中缀值,个位数字,运算符 + - *,prio('*') > prio('+') = prio('-')):
01int calc(string s) { 02 stack<int> num; stack<char> op; 03 auto doOp = [&]() { 04 int b = num.top(); num.pop(); 05 int a = num.top(); num.pop(); 06 num.push(op.top() == '+' ? a + b : 07 op.top() == '*' ? a * b : a - b); 08 op.pop(); 09 }; 10 for (char c : s) { 11 if (isdigit(c)) num.push(c - '0'); 12 else { 13 while (!op.empty() && prio(op.top()) >= prio(c)) doOp(); 14 op.push(c); 15 } 16 } 17 while (!op.empty()) doOp(); 18 return num.top(); 19}
calc("2+3*4") 的返回值是( )。
考点:双栈中缀求值代码(F10)。
(F10)考点:代码逐步执行——2+3*4:读 * 时栈顶 + 优先级低不弹;结尾先弹 * 算 ,再弹 + 算 。
解析:双栈法与手工"先乘后加"殊途同归——读入时不急于算,靠弹栈时机控制顺序。
排除法:选 的人算成了 ;选 的人先算了加法(丢了优先级);选 的人运算对象错位。
阅读下面的程序:
01stack<int> s; 02s.push(1); s.push(2); s.pop(); 03s.push(3); s.push(4); 04cout << s.top() << " " << s.size();
程序的输出是( )。
考点:STL stack 操作序列(F11)。
(F11)考点:STL stack 的 top/size——push 1 2、pop(弹 2)、push 3 4:top = 4、size = 3(1 3 4 三个元素)。
解析:pop 掉的是 2;剩下的 1、3、4,栈顶 4。
排除法:选 4 3 的人 top 对 size 错(漏了 1);选 2 3 的人 top 取了已弹出的 2;选 3 4 的人 top/size 全错。
阅读下面的程序:
01queue<int> q; 02q.push(1); q.push(2); q.pop(); 03q.push(3); 04cout << q.front() << " " << q.back();
程序的输出是( )。
考点:STL queue 操作序列(F12)。
(F12)考点:queue 的 front(队头)/back(队尾)——push 1 2、pop(出 1)、push 3:front = 2、back = 3。
解析:队里剩 2、3;front 是先进入的 2,back 是后进入的 3。
排除法:选 1 3 的人 front 取了已出队的 1;选 2 1 的人 back 错;选 3 2 的人方向全反。
链栈(用单链表头做栈顶)的 push 操作,正确的步骤是( )。
考点:链栈的 push(F13)。
(F13)考点:链栈头插——新节点先指向当前栈顶,再更新 top:node->next = top; top = node;。
解析:顺序不能反——先改 top 会丢掉原链表。
排除法:选"node->next = NULL"的人断链;选"top->next = node"的人接到了栈顶下面(错误方向);选"node->next = top->next"的人在栈非空时丢掉了 top。
补全下面的循环队列入队代码(容量 m):
01void enqueue(int x) { 02 q[rear] = x; 03 ____; 04}
横线处应填( )。
考点:循环队列入队补全(F14)。
(F14)考点:循环队列入队后 rear 取模推进——rear = (rear + 1) % m。
解析:存入 q[rear] 后 rear 后移取模,与出队的 front 推进对称。
排除法:选 rear++ 的人到数组末尾会越界;选 % (m+1) 的人模错了;选移动 front 的人那是出队。
补全括号匹配代码(检测小括号):
01bool match(string s) { 02 stack<char> st; 03 for (char c : s) { 04 if (c == '(') st.push(c); 05 else if (c == ')') { 06 if (____) return false; 07 st.pop(); 08 } 09 } 10 return st.empty(); 11}
横线处应填( )。
考点:括号匹配代码补全(F15)。
(F15)考点:遇 ) 时先检查栈空——空栈说明右括号无匹配,直接返回 false:st.empty()。
解析:顺序是"先判空再弹栈"——不判空直接 top() 在空栈上是未定义行为。
排除法:选 st.size() == 1 的人大小不是判据;选 c == '(' 的人 c 此刻恒是 );选 st.top() == ')' 的人栈里只压左括号。
阅读下面的程序(用栈输出 x 的二进制):
01int x = 6; 02stack<int> st; 03while (x > 0) { st.push(x % 2); x /= 2; } 04while (!st.empty()) { cout << st.top(); st.pop(); }
程序的输出是( )。
考点:用栈输出二进制(F16)。
(F16)考点:栈天然逆序——余数入栈(低位先算出),弹出时高位先出:6 → 110。
解析:6%2=0 入栈、3%2=1 入栈、1%2=1 入栈;弹出 1 1 0——正是二进制 110。不用栈直接输出会得到反的 011。
排除法:选 011 的人忘了栈自动逆序(或没用栈直接输出余数);选 6 的人没做转换;选 0110 的人多了一位。
数组栈有两种常见实现约定:
top 指向栈顶元素,空栈时 top = -1;top 指向栈顶的下一个空位,空栈时 top = 0。两种约定各自合法。下列 push / pop 的配对全部正确的是( )。
考点:两种 top 约定的配对(G1)。
(G1)考点:数组栈两种合法实现约定的配对——约定一(top 指向栈顶元素,空栈 ):push: st[++top](先移到新格再存)、pop: st[top--](先取再减);约定二(top 指向下一空位,空栈 ):push: st[top++](当前格就是空位、存完再移)、pop: st[--top](先退到栈顶再取)。两种约定都对,关键是 push/pop 与约定配对使用。
解析:约定的差别只是 top 停在哪里——写代码时先想清楚"top 此刻指着谁",配对就自然对了(混用会覆盖栈顶或取到空位)。
排除法:选"两种约定的 push 都写 st[top++]"的人约定一会覆盖当前栈顶(没先移位就存);选"两种约定的 pop 都写 st[top--]"的人约定二会取到空位(没先退格就取);选"写法对调"的人两组约定都配错了。
对空栈执行 pop() 且代码没有判空保护,结果是( )。
考点:空栈弹出(G2)。
(G2)考点:无判空保护的空栈 pop = 下标变 -1 的越界访问,未定义行为。
解析:st[top--] 在 top=-1 时访问 st[-1],可能读到垃圾值或崩溃。
排除法:选"返回 0"的人不会自动返回 0;选"自动跳过"的人没有这种保护;选"抛出异常"的人原生数组不会抛异常(stack 容器才会)。
循环队列判满 (rear + 1) % n == front 与判空 front == rear 会冲突吗?最常用的解决方案是( )。
考点:循环队列牺牲一格(G3)。
(G3)考点:判空 front == rear 与判满 (rear+1)%n == front 的区分方案 = 牺牲一个存储单元。
解析:满时 rear 的下一格恰好是 front( rear 停在最后一格不再推进);空时两者直接相等——两种状态可区分。
排除法:选"不会冲突两者恒不同"的人空队列时两者就是相等的;选"用额外的 -1 标记空"的人那是另一种实现(多占一格更常用);选"每次判满前清空队列"的人那样队列就没用了。
顺序队列 head(front)和 tail(rear)的移动规则是( )。
考点:front 与 rear 混淆(G4)。
(G4)考点:head(front)随出队后移、tail(rear)随入队后移。
解析:队头只出不进、队尾只进不出——方向记牢。
排除法:选"head 入队、tail 出队"的人方向全反;选"都只增不减"的人循环队列会取模回绕;选"head、tail 都指向同一元素"的人只在单元素时偶然相同。
容量 100 的顺序队列,经历多次入队出队后 front = tail = 100(数组末尾),虽然中间位置全空却无法再入队。这种现象叫( )。
考点:假溢出(G5)。
(G5)考点:顺序队列 front = tail 到达数组末尾,中间全空却不能入队 = 假溢出,解决 = 循环队列。
解析:下标无法前进但实际有空间——"假"就假在空间其实还有。
排除法:选"真溢出"的人真溢出是空间真的满了;选"内存泄漏"的人那是动态内存管理问题;选"栈溢出"的人这是队列不是栈。
不用循环结构时,顺序队列出队操作的另一种实现是( )。
考点:顺序队列出队搬家(G6)。
(G6)考点:不用循环结构的替代方案 = 出队后整体前移,代价 (所以实际多用循环队列)。
解析:每出队一次搬一次家,效率低;循环队列用取模让下标回绕,免搬家。
排除法:选"删除数组第一个元素(其余前移一位)"的人描述的正是搬家本身但没点出代价与对比;选"从队尾删除"的人队尾不能删;选"无法实现"的人可以实现只是低效。
下列括号序列中,完全匹配(合法)的是( )。
考点:匹配判定(H1)。
(H1)考点:匹配三查——扫描完栈空、无多余右括号、无剩余左括号。只有 ()() 全过。
解析:(() 剩 1 个左括号;())( 第二个右括号时栈已空;()( 剩 1 个左括号。
排除法:选 (() 的人左括号没配完;选 ())( 的人右括号多且后面还有孤立左括号;选()( 的人同样左括号剩余。
括号序列 ((())) 在栈法匹配过程中,栈的最大高度(最大嵌套深度)是( )。
考点:最大嵌套深度(H2)。
(H2)考点:栈法处理 ((())) 时栈的最大高度 = 最深嵌套层数 3。
解析:三个左括号连续入栈后才开始弹——最大高度 3 = 嵌套深度。
排除法:选 的人数错层;选 的人没看嵌套;选 的人把序列长度当深度。
下列序列中,多种括号匹配正确的是( )。
考点:多种括号与交叉(H3)。
(H3)考点:多括号匹配规则——必须同型且不交叉:([]) 合法;([)] 交叉非法。
解析:弹栈时弹出的左括号必须与当前右括号同型——([)] 弹出 [ 遇到 ),不同型,非法。
排除法:选 ([)] 的人被"数量相等"迷惑(数量对但交叉);选 [(]) 的人同上;选 ((] 的人数量都不等。
括号序列 ((() 至少再添加( )个括号才能变成完全匹配。
考点:至少补几个括号(H4)。
(H4)考点:扫描完统计剩余未配左括号数——((() 剩 2 个 ((栈深 2),补 2 个 ) 即匹配。
解析:右括号出现时及时弹栈,最后栈里剩几个左括号就补几个右括号。
排除法:选 的人少数一个;选 的人多数;选 的人没算剩余。
对括号能组成的合法括号序列共有( )种。
考点:合法括号序列计数(H5)。
(H5)考点:n 对括号的合法序列数 = 卡特兰数——:()()()、()(())、(())()、(()())、((()))。
解析:非法的如 ())(( 等被"任意前缀左括号数 ≥ 右括号数"条件排除。
排除法:选 的人把部分非法序列算入;选 的人少算;选 的人那是 的值(4 对)。
用栈法处理括号序列 (()()),处理完全部字符后栈的状态是( )。
考点:匹配过程的栈状态(H6)。
(H6)考点:(()()) 完全匹配——处理完栈空。
解析:每个左括号都被后续右括号配对弹出,扫描结束栈空 = 匹配成功的标志。
排除法:选"剩 个 ("的人少数了弹栈;选"剩 个 ("的人多数;选"不确定"的人结果是确定的。
函数 f 调用 g、g 调用 h。关于返回顺序,正确的是( )。
考点:函数调用栈(I1)。
(I1)考点:函数调用靠栈管理——f→g→h 调用时 h 的记录最后压入、最先弹出:h 先返回。
解析:调用压栈、返回弹栈——LIFO 保证嵌套调用的正确返回顺序,这是递归能工作的底层机制。
排除法:选"f 先返回"的人调用链反了;选"同时返回"的人返回有严格顺序;选"不确定"的人顺序由栈结构唯一确定。
递归函数 f(3) 依次调用 f(2)、f(1)。递归最深时,函数调用栈中 f 的活动记录有( )层。
考点:递归与栈深度(I2)。
(I2)考点:f(3)→f(2)→f(1) 递归链——最深时 3 层活动记录同时在栈上。
解析:f(3) 未返回时调 f(2)、f(2) 未返回时调 f(1)——三个帧并存,深度 3。
排除法:选 的人漏了最外层;选 的人只数了最深一层;选 的人多算。
深度优先搜索(DFS)和广度优先搜索(BFS)分别主要借助( )实现。
考点:DFS 与 BFS 的工具(I3)。
(I3)考点:DFS 借助栈(一路深入、回溯退栈)、BFS 借助队列(逐层扩展)。
解析:递归 DFS 隐式用调用栈,显式 DFS 手工栈;BFS 天然层次序用队列。
排除法:选"队列、栈"的人配反;选"都是栈"的人 BFS 层序不成立;选"都是队列"的人 DFS 深入序不成立。
BFS 从起点出发逐层向外扩展:第 1 层的邻居先处理完,才会处理第 2 层。保证这种"层次顺序"的数据结构特性是( )。
考点:BFS 逐层扩展(I4)。
(I4)考点:保证"层次顺序"的结构特性 = 先进先出——第 k 层先发现的节点先扩展,才能轮到第 k+1 层。
解析:若用后进先出,最新的节点(更深层)会插队,层序被破坏(那就成了 DFS)。
排除法:选"后进先出"的人那是 DFS;选"随机/按值排序"的人与层次无关。
用栈判断字符串 abba 是否回文:把前一半 ab 压栈,再逐个扫描后一半与弹出的元素比对。比对结果是( )。
考点:用栈判断回文(I5)。
(I5)考点:栈法回文——前半 ab 入栈,后半从左到右扫:'b' 对弹出 b ✓、'a' 对弹出 a ✓——abba 是回文。
解析:栈把前半倒过来,与后半顺序比对——倒过来相等即回文。
排除法:选"第 1 次比对 a 与 b"的人把弹栈顺序弄错(扫到 b 弹出的就是 b);选"只需比对一次"的人要比完整个后半;选"栈法不能判断"的人方法正确有效。
字符串 abc 的每个字符依次入栈,然后全部弹出输出,得到的是( )。
考点:用栈逆序输出(I6)。
(I6)考点:栈的逆序能力——abc 依次入栈全弹出:cba。
解析:先进后出 = 完整逆转——输出二进制(F16)、字符串翻转都是这个原理。
排除法:选 abc 的人没经过栈;选 acb、bca 的人部分弹出顺序错。
元素按 3, 1, 2 的顺序依次到达栈。仅借助这个栈,得到输出 1 2 3 的操作序列是( )。
考点:乱序入栈定输出(J1)。
(J1)考点:乱序到达 + 栈中转——3, 1, 2 到达:3 入栈等、1 入即出、2 入即出、最后弹 3:输出 1 2 3。
解析:3 虽先到但被压在底,1、2 借栈顶先出——"先到不一定先出"正是栈的调度能力。
排除法:选"不可能实现"的人没找到操作序列;选"三个全入再全出"的人输出是 2 1 3;选"3 入栈即出、1 入栈即出、2 入栈即出"的人输出 3 1 2。
初始空的栈 S 和队列 P,依次处理 7, 5, 8, 3, 1, 4, 2:奇数压入 S、偶数入 P。全部处理完后先弹尽 S(从栈顶)再出尽 P(从队头),输出序列是( )。
考点:奇偶分流完整模拟(J2)。
(J2)考点:分流 + 双结构输出——奇数 7 5 3 1 入栈(底→顶),弹出从顶:1 3 5 7;偶数 8 4 2 入队,出队:8 4 2;拼接 1 3 5 7 8 4 2。真题 2025 年考过此问法。
解析:两个结构各自输出再按题序拼接——注意"从栈顶弹出"是逆入序、"从队头出队"是保序。
排除法:选 7 5 3 1 8 4 2 的人把栈按入序输出(忘了从顶弹);选 8 4 2 7 5 3 1 的人先输出了队列部分;选 1 3 5 7 2 4 8 的人把队列也逆序了。
对初始空栈依次执行:push 1、push 2、push 3、pop、push 4、push 5、pop、pop、push 6。此时栈中从栈底到栈顶是( )。
考点:混合操作追踪(J3)。
(J3)考点:逐步追踪——123 弹 3 → 12;压 45 弹 5 弹 4 → 12;压 6 → 1 2 6。
解析:每步维护栈的完整状态,pop 总是取当前栈顶。
排除法:选 1 2 4 6 的人第二次 pop 没执行;选 1 6 的人多弹了两次;选 1 2 3 6 的人第一次 pop 没执行。
用队列模拟栈时,push 操作的正确做法及其代价是( )。
考点:队列实现栈的 push(J4)。
(J4)考点:队列模拟栈——push 直接入队 O(1)(代价转移到 pop)。
解析:与 E9 呼应:这种实现 push 快 pop 慢;另一种"push 时就转"的写法则 push O(n)、pop O(1)。
排除法:选"先转移 O(n)"的人那是另一种实现的 push;选"排序"的人无排序需求;选"两队列同时 O(n)"的人不必。
两个栈共享一个长度为 的数组:栈 1 的 top1 从 向右增长,栈 2 的 top2 从 向左增长。判"栈满"的条件是( )。
考点:两栈共享空间(J5)。
(J5)考点:共享栈判满——两栈顶相向增长,相遇即满:top1 + 1 == top2。
解析:top1 从 -1 向右、top2 从 m 向左;当 top2 紧邻 top1 之右时(top1+1==top2)再无空位。
排除法:选"top1 == m-1 && top2 == 0"的人那是两端各自满(共享栈整体满时未必两端同时满);选"top1+top2 == m"的人恒等式不是判满;选"top1 == top2"的人两者永不相等(相邻即满)。
双栈法求中缀表达式的值(含括号,括号优先级最高)。表达式 (2+3)*4 的值是( )。
考点:双栈求值含括号(J6)。
(J6)考点:括号在双栈法中优先级最高——(2+3)*4:括号内先算 5,再乘 4 = 。
解析:遇 ( 直接入栈、遇 ) 连续弹到 (——括号内的运算先完成,再参与外部运算。
排除法:选 的人算成了 2+3*4(丢了括号);选 的人括号作用域错;选 的人运算对象错位。
1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 char st[100]; 5 int main() { 6 scanf("%s", st); 7 int n = strlen(st); 8 for (int i = 1; i <= n; ++i) { 9 if (n % i == 0) { 10 char c = st[i - 1]; 11 if (c >= 'a') 12 st[i - 1] = c - 'a' + 'A'; 13 } 14 } 15 printf("%s", st); 16 return 0; 17 }
输入的字符串只能由小写字母或大写字母组成。( )
若将第 行的 i = 1 改为 i = 0,程序运行时会发生错误。( )
若将第 行的 i <= n 改为 i * i <= n,程序运行结果不会改变。( )
若输入的字符串全部由大写字母组成,那么输出的字符串就跟输入的字符串一样。( )
若输入的字符串长度为 ,那么输入的字符串跟输出的字符串相比,至多有( )个字符不同。
若输入的字符串长度为( ),那么输入的字符串跟输出的字符串相比,至多有 个字符不同。
下图中所使用的数据结构是( )。图示依次执行“压入 A、压入 B、弹出 B、压入 C”。
对于入栈顺序为 a, b, c, d, e 的序列,下列( )不是合法的出栈序列。
表达式 a*(b+c)*d 的后缀表达式为( ),其中 * 和 + 是运算符。
有 个元素,按照 、、、、、 的顺序进入栈 S,请问下列哪个出栈序列是非法的( )。
对假设栈 S 和队列 Q 的初始状态为空。存在 e1~e6 六个互不相同的数据,每个数据按照进栈 S、出栈 S、进队列 Q、出队列 Q 的顺序操作,不同数据间的操作可能会交错。已知栈 S 中依次有数据 e1、e2、e3、e4、e5 和 e6 进栈,队列 Q 依次有数据 e2、e4、e3、e6、e5 和 e1 出队列。则栈 S 的容量至少是( )个数据。
对表达式 a+(b-c)*d 的前缀表达式为( ),其中 +、-、* 是运算符。
以下对数据结构的表述不恰当的一项为:( )。
后缀表达式 6 2 3 + - 3 8 2 / + * 2 ^ 3 + 对应的中缀表达式是( )。
给定一个空栈,支持入栈和出栈操作。若入栈操作的元素依次是 1 2 3 4 5 6,其中 1 最先入栈、6 最后入栈,下面哪种出栈顺序是不可能的?( )
给定一个初始为空的整数栈 和一个空的队列 。我们按顺序处理输入的整数队列 。对于队列 中的每一个数,执行以下规则:如果该数是奇数,则将其压入栈 ;如果该数是偶数,且栈 非空,则弹出一个栈顶元素,并加入到队列 的末尾;如果该数是偶数,且栈 为空,则不进行任何操作。当队列 中的所有数都处理完毕后,队列 的内容是什么?( )