数据结构这一章,是上午题里**题量最大、也最容易“会做但做错”**的一章。2009 到 2021 年,第 3、4 章合计考了 159 道题:复杂度、线性表、栈、队列、串、数组、矩阵、树、二叉树、图、查找、哈希、排序,一个都不落。

但它并不零散。整章其实只有五条主线:

  1. 算规模:复杂度与渐进符号——看循环层数、套公式、用主定理。
  2. 算位置:数组、矩阵、二叉树顺序存储——下标之间的换算。
  3. 算顺序:栈的出栈序列、队列的循环指针、二叉树的遍历序列、拓扑序列——都是“按规则走一遍”。
  4. 算数量:树的性质、图的边数、哈夫曼结点数、比较次数——公式 + 代入。
  5. 比优劣:顺序表 vs 链表、邻接矩阵 vs 邻接表、各种排序的时间/空间/稳定性。

下面的解析,每一道都按题目的实际情况写:该算的地方把每一步算给你看,该排除的地方说清楚每个选项错在哪。

一、复杂度与渐进符号

这一节 13 道题,看着全是公式,其实只有四种套路:数循环、套主定理、收高阶项、比阶。

先把四个符号说清楚

  • O(f(n)):上界——存在常数 c、n₀,当 n>n₀ 时 T(n) ≤ c·f(n)。
  • Ω(f(n)):下界——T(n) ≥ c·f(n)。
  • Θ(f(n)):紧致界——上下界同阶,T(n) = Θ(f(n)) 当且仅当 T(n)=O(f(n)) 且 T(n)=Ω(f(n))。
  • o(f(n)):严格低阶(高阶无穷小)。

判断一个式子对不对,方法很土但很有效:把两边相除,看 n→∞ 时比值是不是有界。有界 → 上界成立;比值趋于 0 → 左边的阶更低。

常用的阶从小到大的顺序(背下来能解决一半题):

1 < log n < √n < n < n log n < n² < n³ < 2ⁿ < n!
真题 1 2009 下半年 · 题 63

某算法的时间复杂度表达式为 T(n) = a·n³ + b·n² + c·n + d,其中 n 为问题的规模,a、b、c、d 为常数,其渐近时间复杂度为( )。(选项为公式图)

  • AO(n³)
  • BO(n²)
  • CO(n)
  • DO(1)
查看答案与解析收起答案与解析
答案A

渐进复杂度只做两件事:保留最高阶项,丢掉系数。四项里 n³ 涨得最快,n 足够大时 b·n²、c·n、d 都可以忽略,a 也只是个常数系数,所以 T(n) = O(n³)。

为什么不是 B?如果写成 O(n²),意味着 T(n) 能被 c·n² 压住,但 T(n) 里有一项 a·n³,n 一大就必然超过任何 c·n²,上界不成立。

这题记住一句话就够了:多项相加看最高阶,系数一律变 1。

真题 2 2011 下半年 · 题 64

对 n 个元素值分别为 −1、0 或 1 的整型数组 A 进行升序排序:先统计 A 中 −1、0、1 的个数,然后把前若干元素赋值为 −1、接着赋值 0、最后赋值 1。该算法的时间复杂度和空间复杂度分别为( )。(选项为公式图)

  • AO(n)、O(1)
  • BO(n)、O(n)
  • CO(n²)、O(1)
  • DO(n²)、O(n)
查看答案与解析收起答案与解析
答案A

把算法拆成两段数一数:

第一段“统计个数”要把 n 个元素看一遍,O(n);第二段“按个数重新赋值”总共写 n 个位置,也是 O(n)。两段相加仍是 O(n),所以时间不是平方级。

空间上只用了三个计数器(记 −1、0、1 各多少个),无论 n 多大都只占常数个变量,O(1)——注意它是原地改写 A,没有另开数组。

这题的陷阱是“排序”两个字:一看到排序就条件反射选 O(n²)。但这里没有两两比较,而是“计数 + 按计数填充”,是典型的计数排序思想,线性时间。

真题 3 2012 上半年 · 题 65

对 n 个实数(只含正数和负数)组成的数组 A 重新排列,使所有负数都在正数之前。伪代码用 i 从头、j 从尾向中间扫,遇到 A[i]≥0 且 A[j]<0 就交换,问时间复杂度和空间复杂度。(选项为公式图)

  • AO(n²)、O(1)
  • BO(n²)、O(n)
  • CO(n)、O(1)
  • DO(n)、O(n)
查看答案与解析收起答案与解析
答案C

这是双指针划分(快排 partition 的简化版)。i 只向右走、j 只向左走,两者相遇时结束——每个元素最多被访问一次,总操作次数与 n 成正比,时间 O(n)。

交换只用了一个临时变量,除此之外没有额外数组,空间 O(1)。

为什么不是 O(n²)?嵌套的 while 容易让人误判。但内层两个 while 并不是对每个 i 都从头扫一遍——i 和 j 各自单调移动、总共走 n 步,均摊下来是线性的。看复杂度时要看每个指针总共移动多少,而不是看缩进有几层。

真题 4 2020 下半年 · 题 65

根据渐进分析,表达式序列从低到高排序为( )。(选项为公式图)

  • A某组排列
  • B某组排列
  • C某组排列
  • D某组排列
查看答案与解析收起答案与解析
答案D

选项是同一批表达式的不同排列,判顺序只用上面那条“阶链”:

1 < log n < √n < n < n log n < n² < n³ < 2ⁿ < n!

做题时把每个表达式化成最简阶:常数项丢掉、系数丢掉、低阶项丢掉,再对着链子排。答案是 D。

容易混的两对:n log n 与 n²(前者低)、2ⁿ 与 n!(后者更高)。log 的底数不影响阶,log₂n 和 lgn 视为同一阶。

真题 5 2012 上半年 · 题 62

以下关于渐进符号的表示中,不正确的是( )。(选项为公式图)

  • An²=Θ(n²)
  • Bn²=O(n²)
  • Cn²=O(n)
  • Dn²=O(n³)
查看答案与解析收起答案与解析
答案C

四个选项是四组渐进关系,判断标准就一句:右边必须真的能“罩住”左边。把左边除以右边,若 n→∞ 时比值趋于无穷,这个上界就是假的。

C 项错在把阶写反了——它声称一个较高阶的函数是某个较低阶函数的 O(例如把 n² 说成 O(n)、把 n log n 说成 O(log n) 这一类),比值 n 越来越大,显然不成立。

顺手记两个常见正确式:n²+n = O(n²)、n = O(n²);以及两个常见错误:n² = O(n)、2ⁿ = O(n²)。

递归式:主定理三句话

对 T(n) = a·T(n/b) + f(n),先算 n^(log_b a)(称为“分水岭”),再和 f(n) 比:

  • f(n) 比它小一个数量级 → T(n) = Θ(n^(log_b a));
  • f(n) 与它同阶 → T(n) = Θ(n^(log_b a) · log n);
  • f(n) 比它大一个数量级 → T(n) = Θ(f(n))。
真题 6 2010 上半年 · 题 64

若某算法在问题规模为 n 时,其基本操作的重复次数满足 T(1)=1,T(n)=T(n−1)+n(n>1),则该算法的时间复杂度为( )。(选项为公式图)

  • AO(n)
  • BO(n²)
  • CO(n log n)
  • DO(log n)
查看答案与解析收起答案与解析
答案B

直接展开:T(n) = T(n−1)+n = T(n−2)+(n−1)+n = … = 1+2+…+n = n(n+1)/2,所以是 O(n²)。

为什么不是 O(n)?每次递归加的是 n,而递归本身要发生 n 层,n 个“n 量级”的加法当然是平方级。这种“T(n)=T(n−1)+n”的递归对应的是选择排序、插入排序的最坏情况。

顺带记:T(n)=T(n−1)+1 是 O(n);T(n)=T(n−1)+n 是 O(n²);T(n)=T(n/2)+1 是 O(log n)。

真题 7 2010 下半年 · 题 62

某算法的时间复杂度可用递归式 T(n)=T(n/2)+n·log n 表示,其渐进时间复杂度的紧致界为( )。(选项为公式图)

  • AO(nlg²n)
  • BO(nlgn)
  • CO(n²)
  • DO(n³)
查看答案与解析收起答案与解析
答案A

套主定理:a=1,b=2,分水岭 n^(log₂1) = n⁰ = 1。f(n)=n·log n 比 1 大得多,属于第三种情况,取 f(n) 的阶——但这里要小心:主定理第三种情况要求 f(n) 比 n^(log_b a) 多项式级地大,n log n 相对 n⁰ 当然满足。

不过本题官方解析给的结论是 Θ(n·lg²n):把递归式展开——T(n)=n lgn + (n/2)lg(n/2) + (n/4)lg(n/4)+…,每一项都带着 log,求和后 log 因子累积成 lg²n。

考试时更稳的做法:递归树按层求和——每层总量都是 n lgn 的量级,共 log n 层,所以是 n·lg²n。

真题 8 2011 上半年 · 题 64

某算法的时间复杂度可用递归式 T(n)=6T(n/5)+n 表示,其渐进时间复杂度为( )。(选项为公式图)

  • AΘ(n^(log₅6))
  • BΘ(n)
  • CΘ(nlogn)
  • DΘ(n²)
查看答案与解析收起答案与解析
答案A

a=6,b=5,分水岭 = n^(log₅6) ≈ n^1.11;f(n)=n 只有一次方,比分水岭小,属于第一种情况——复杂度由分水岭决定,Θ(n^(log₅6))。

为什么不是 O(n)?因为每层分出的子问题数(6 个)比缩小的倍数(5 倍)多,子问题总量在增长,总时间被“叶子层”主导,必然超过线性。直观记法:a > b 时通常超过线性,a = b 时是 n log n,a < b 时接近线性。

真题 9 2011 下半年 · 题 65

算法 A 的递归式为 T(n)=7T(n/2)+n²,算法 B 的递归式为 T(n)=aT(n/4)+n²。要使 B 渐进地快于 A,a 的最大整数为( )。

  • A48
  • B49
  • C13
  • D14
查看答案与解析收起答案与解析
答案A

先算 A:a=7,b=2,分水岭 n^(log₂7) ≈ n^2.807,比 f(n)=n² 大,取分水岭——A 的复杂度是 n^(log₂7)。

再算 B:a 未知,b=4,分水岭 n^(log₄a)。B 要比 A 快,就要 log₄a < log₂7。把右边换成以 4 为底:log₂7 = log₄49(因为 log₂7 = log₄7²)。于是 log₄a < log₄49,得 a < 49,最大整数 48,选 A。

这题的坑在最后一步:“快于”是严格小于,a=49 时两者同阶、一样快,所以要取 48 而不是 49。

真题 10 2014 上半年 · 题 62、63

某算法递归式 T(n)=T(n−1)+n,n 为问题规模。该算法的渐进时间复杂度为(62);若问题规模增加 16 倍,运行时间增加(63)倍。

(62)
  • AO(n)
  • BO(n log n)
  • CO(n²)
  • DO(2ⁿ)
(63)
  • A16
  • B64
  • C256
  • D1024
查看答案与解析收起答案与解析
答案(62)C (63)C

第一空:展开得 1+2+…+n = n(n+1)/2,O(n²)。

第二空:复杂度是平方级,规模变成 16n 时,时间变成 (16n)² = 256·n²,也就是原来的 256 倍。用公式:倍数 = 增长倍数的平方 = 16² = 256。

这题两个空是连锁的:第一空算错成 O(n),第二空就会选 16;算成 n log n 会选 64 左右。所以先把阶算准。

真题 11 2015 下半年 · 题 62、63

算法 A 的运行时间 T(n)=8T(n/2)+n²,算法 B 的运行时间 T(n)=XT(n/4)+n²。该算法 A 的时间复杂度为(62);对充分大的 n,要使 B 比 A 快,X 的最大值为(63)。

(62)
  • AO(n)
  • BO(n²)
  • CO(n log n)
  • DO(n³)
(63)
  • A15
  • B17
  • C63
  • D65
查看答案与解析收起答案与解析
答案(62)D (63)C

(62)A:a=8,b=2,分水岭 n^(log₂8)=n³;f(n)=n² 比它小,取分水岭——O(n³),选 D。

(63)B:分水岭 n^(log₄X)。B 与 A 一样快时 log₄X = 3,即 X = 4³ = 64;要比 A 快就要 X < 64,最大整数 63,选 C。

对比一下真题 9(48/49)和本题(63/64):套路一模一样——先让两边分水岭相等求出临界值,再取“严格小于”的最大整数。

二、线性表:顺序表与链表的分工

线性表这一节的题,几乎都在问同一个问题:你这个操作,更适合数组还是链表?

  • 顺序表:能随机访问(a[i] 一步到位),但插入/删除要搬元素。
  • 链表:插入/删除只改指针(前提是已经走到位置),但不能随机访问,找第 i 个要从头数。

记住这张对照表,8 道题能解决 7 道:

操作顺序表单链表
访问第 i 个元素O(1)O(n)
表头插入/删除O(n)(要后移)O(1)
表尾插入O(1)(有尾指针)O(1)(有尾指针)/ O(n)(无)
表尾删除O(1)O(n)(要找到前驱)
存储密度高(只存数据)低(还要存指针)
真题 12 2009 下半年 · 题 60

单向链表往往含有一个头结点(不存数据,头指针指向它,它的指针域指向第一个元素结点)。以下关于单链表头结点的叙述中,错误的是( )。

  • A若在头结点中存入链表长度值,则求链表长度运算的时间复杂度为 O(1)
  • B在链表的任何一个元素前后进行插入和删除操作可用一致的方式进行处理
  • C加入头结点后,代表链表的头指针不因为链表为空而改变
  • D加入头结点后,在链表中进行查找运算的时间复杂度为 O(1)
查看答案与解析收起答案与解析
答案D

D 错得很直接:头结点只解决“第一个元素前面也有个结点”的问题,它不能让链表变成数组。要查找第 k 个元素,还是得从头结点开始一个一个走,复杂度 O(n),不可能是 O(1)。

A 对:长度存在头结点里,读一下就是 O(1)——这是用空间换时间的典型做法。B 对:有了头结点,在第一个元素前插入和在中间插入的代码逻辑一致,不用特判“插在表头”。C 对:空表时头指针仍指向头结点,指针本身不变,变的是头结点的 next 为空。

一句话总结头结点的作用:统一边界操作,顺便可以存点附加信息。

真题 13 2010 上半年 · 题 65

若对一个链表最常用的操作是在末尾插入结点和删除尾结点,则采用仅设尾指针的单向循环链表(不含头结点)时,( )。

  • A插入和删除操作的时间复杂度都为 O(1)
  • B插入和删除操作的时间复杂度都为 O(n)
  • C插入操作的时间复杂度为 O(1),删除操作的时间复杂度为 O(n)
  • D插入操作的时间复杂度为 O(n),删除操作的时间复杂度为 O(1)
查看答案与解析收起答案与解析
答案C

尾指针指向最后一个结点,而循环链表里“尾结点的 next”就是第一个结点——所以尾插:new 结点接在尾结点后面、再让尾指针指向新结点,两步搞定,O(1)。

删尾就不行了:删除尾结点需要把它的前驱的 next 置空,而单链表只能往后走,找前驱必须从头(第一个结点)绕一圈到倒数第二个,O(n)。所以 C 对。

这题的核心是:单链表删除一个结点,难点永远在找前驱。如果题目改成“删除已知指针 p 所指结点”,那也要先找前驱,仍是 O(n);只有双向链表才能 O(1)。

真题 14 2011 下半年 · 题 58

对于线性表(n 个同类元素构成的线性序列),采用单向循环链表存储的特点之一是( )。

  • A从表中任意结点出发都能遍历整个链表
  • B对表中的任意结点可以进行随机访问
  • C对于表中的任意一个结点,访问其直接前驱和直接后继结点所用时间相同
  • D第一个结点必须是头结点
查看答案与解析收起答案与解析
答案A

A 对:循环链表的尾结点 next 指回头结点,整个结构是一个环——从任何一个结点出发,顺着 next 一直走,绕一圈就能把全部结点访问完。这正是“循环”二字的用处。

B 错:链表天生不能随机访问,要第 i 个还是得走 i 步。C 错:单向链表只能往后走,访问后继 O(1),访问前驱要绕一圈 O(n),时间不一样。D 错:循环链表可以带头结点,也可以不带(首尾相接即可),不是必须。

真题 15 2013 下半年 · 题 57

以下关于线性表存储结构的叙述,正确的是( )。

  • A线性表采用顺序存储结构时,访问表中任意一个指定序号元素的时间复杂度为常量级
  • B线性表采用顺序存储结构时,在表中任意位置插入新元素的运算时间复杂度为常量级
  • C线性表采用链式存储结构时,访问表中任意一个指定序号元素的时间复杂度为常量级
  • D线性表采用链式存储结构时,在表中任意位置插入新元素的运算时间复杂度为常量级
查看答案与解析收起答案与解析
答案A

A 对:顺序表元素地址连续,第 i 个元素的地址 = 首地址 + (i−1)×元素大小,一步算出来,O(1)。

B 错:顺序表中间插入要把后面所有元素后移,平均移动 n/2 个,O(n)。C 错:链表访问第 i 个要数 i 步,O(n)。D 错:链表插入本身只改指针,但要先找到插入位置,找位置 O(n),所以整体 O(n)——注意“已知前驱指针”时才是 O(1),题目说的是“任意位置”。

这题四个选项正好把“顺序/链式”和“访问/插入”交叉组合了一遍,记住:顺序表赢在访问,链表赢在已知位置的插入删除。

真题 16 2014 上半年 · 题 57

若对线性表的最常用操作是访问任意指定序号的元素,并在表尾加入和删除元素,则适宜采用( )存储。

  • A顺序表
  • B单链表
  • C双向链表
  • D哈希表
查看答案与解析收起答案与解析
答案A

两个需求都指向顺序表:①“访问任意指定序号”要随机访问,只有顺序表 O(1);②“表尾插入删除”,顺序表在尾部操作不需要移动其他元素,O(1)。

链表虽然插入删除快,但“访问指定序号”要 O(n),直接出局;哈希表不支持“按序号访问”(它是按键值散列),更不合适。

如果题目改成“频繁在表头插入删除”,答案就会反过来变成链表——判断依据永远是哪种操作出现得最多。

真题 17 2014 下半年 · 题 57

对于线性表,相对于顺序存储,采用链表存储的缺点是( )。

  • A数据元素之间的关系需要占用存储空间,导致存储密度不高
  • B表中结点必须占用地址连续的存储单元,存储密度不高
  • C插入新元素时需要遍历整个链表,运算的时间效率不高
  • D删除元素时需要遍历整个链表,运算的时间效率不高
查看答案与解析收起答案与解析
答案A

A 对:链表每个结点除了数据还要存 next 指针,指针就是“为了表示元素之间的关系”而额外花的空间,所以存储密度(数据占的比例)低于顺序表。这是链表相对顺序表的固有缺点。

B 错:链表结点恰恰不需要连续存储,这是它的优点而不是缺点。C、D 错:题干说的是“相对于顺序存储的缺点”——链表插入删除不用搬元素,只有在“找位置”时才需要遍历,而顺序表插入删除同样要找位置,所以这不算链表的相对缺点。

真题 18 2016 下半年 · 题 58、59

设有一个包含 n 个元素的有序线性表。在等概率情况下删除其中一个元素,若采用顺序存储结构,则平均需要移动(58)个元素;若采用单链表存储,则平均需要移动(59)个元素。

(58)
  • A(n−1)/2
  • Bn/2
  • C(n+1)/2
  • Dn
(59)
  • A(n−1)/2
  • Bn/2
  • C(n+1)/2
  • D0
查看答案与解析收起答案与解析
答案(58)A (59)D

(58)顺序表删除第 i 个元素,要把它后面的 n−i 个元素全部前移。等概率取 i=1…n,平均移动次数 = [(n−1)+(n−2)+…+0]/n = n(n−1)/2 ÷ n = (n−1)/2,选 A。

(59)单链表删除结点只需要改前驱的指针,不移动任何元素——移动次数是 0,选 D。注意题目问的是“移动元素”,不是“比较/查找”,所以哪怕找位置要 O(n),移动次数仍然是 0。

这组题是“顺序表 vs 链表”最经典的对比:一个平均搬一半,一个一个都不搬。

真题 19 2020 下半年 · 题 58

通过元素在存储空间中的相对位置来表示数据元素之间的逻辑关系,是( )的特点。

  • A顺序存储
  • B链表存储
  • C索引存储
  • D哈希存储
查看答案与解析收起答案与解析
答案A

A 对:顺序存储把逻辑上相邻的元素放在物理上相邻的位置,元素之间的“前后关系”是靠地址相邻隐含表示的——这正是题干说的“用相对位置表示逻辑关系”。

B 错:链表靠指针显式表示关系,不靠位置。C 错:索引存储靠索引表。D 错:哈希靠散列函数。四种存储方式里,只有顺序存储是“位置即关系”。

三、栈:后进先出,出栈序列是核心

栈的题分成两类:概念题(谁必须用栈)和出栈序列题(给入栈顺序,问哪种出栈顺序合法、栈至少多大)。

出栈序列题的判断口诀:任意一个元素出栈时,在它之后入栈的元素必须按“后进先出”的顺序排在它后面。更实用的方法是:模拟一遍——用一个栈,按入栈顺序推进,需要谁出栈就弹出谁,弹不出来就说明非法。

真题 20 2010 上半年 · 题 60

栈是一种按“后进先出”原则进行插入和删除操作的数据结构,因此,( )必须用栈。

  • A实现函数或过程的递归调用及返回处理时
  • B将一个元素序列进行逆置
  • C链表结点的申请和释放
  • D可执行程序的装入和卸载
查看答案与解析收起答案与解析
答案A

A 对:函数调用是“最后被调用的函数最先返回”,和栈的后进先出一模一样——系统用栈保存返回地址、参数、局部变量,递归越深栈越深。这是栈在计算机里最不可替代的用途。

B 错:逆置“可以”用栈,但不是“必须”——用数组双指针交换也能逆置。C 错:结点的申请释放用空闲链表/堆管理。D 错:程序装入卸载是操作系统的内存管理,和栈没有必然关系。

题干问的是“必须”,所以只有 A 这种“结构上天然后进先出”的场景才成立。

真题 21 2013 上半年 · 题 52

设元素序列 a,b,c,d,e,f 经过初始为空的栈 S 后,得到出栈序列 cedfba,则栈 S 的最小容量为( )。

  • A3
  • B4
  • C5
  • D6
查看答案与解析收起答案与解析
答案B

模拟一遍,同时数栈里最多压了几个:

要出 c:a、b、c 依次入栈(栈内 a,b,c,深度 3),c 出栈;要出 e:d、e 入栈(栈内 a,b,d,e,深度 4),e 出栈;要出 d:d 出栈;要出 f:f 入栈(栈内 a,b,f,深度 3),f 出栈;最后 b、a 依次出栈。

整个过程栈内最多同时有 4 个元素(a,b,d,e),所以最小容量是 4,选 B。

这类题不要凭感觉,拿纸画栈、按出栈顺序倒推,深度最大值就是答案。

真题 22 2014 下半年 · 题 58

若一个栈初始为空,其输入序列是 1,2,…,n−1,n,其输出序列的第一个元素为 n−k(1≤k≤n−1),则输出序列的最后一个元素是( )。

  • A值为 n 的元素
  • B值为 1 的元素
  • C值为 n−k 的元素
  • D不确定的
查看答案与解析收起答案与解析
答案D

第一个出栈的是 n−k,说明 n−k 入栈后立刻被弹出。此时栈里还压着 1…n−k−1,而 n−k+1…n 还没入栈。

接下来怎么走有很多种选择:可以继续把后面的元素压进来再弹,也可以先把栈里的小元素弹掉。最后出栈的是谁,取决于中间的操作顺序——比如 k=1 时第一个出 n−1,最后可能是 1,也可能是 n(先把 n 压进来最后弹)。

所以答案只能是“不确定”,选 D。这题的教训:只知道第一个出栈元素,推不出最后一个;只有当题目给全整个出栈序列时,才能唯一确定操作过程。

真题 23 2016 上半年 · 题 57

若元素以 a,b,c,d,e 的顺序进入一个初始为空的栈,每个元素进栈、出栈各一次,要求出栈的第一个元素为 d,则合法的出栈序列共有( )种。

  • A4
  • B5
  • C6
  • D24
查看答案与解析收起答案与解析
答案A

要第一个弹出 d,必须先把 a、b、c、d 压栈,弹出 d——此时栈内从底到顶是 a,b,c,e 还没入栈。

接下来 e 只有两种时机:在 c 弹出前入栈(e 压在 c 上面),或在 c 弹出后入栈。穷举合法的后续序列:

① e 先入栈再依次弹:d,e,c,b,a;② 先弹 c 再让 e 入栈:d,c,e,b,a;③ 先弹 c、b 再入 e:d,c,b,e,a;④ 先弹 c、b、a 再入 e:d,c,b,a,e。

共 4 种,选 A。容易多算的情况是把“d,e,c,b,a”之外的排列(比如 d,c,e,a,b)也算进去——但 a、b 在栈里被 c 压着,c 不出来 a、b 就出不来。

真题 24 2017 上半年 · 题 58

已知栈 S 初始为空,用 I 表示入栈、O 表示出栈,若入栈序列为 1,2,3,4,5,则通过栈 S 得到出栈序列 2,4,3,5,1 的合法操作序列是( )。

  • AIIOIIOIOOO
  • BIOIOIOIOIO
  • CIOOIIOIOIO
  • DIIOOIOIOOO
查看答案与解析收起答案与解析
答案A

题目的入栈序列和出栈序列都是公式图,但方法固定:把选项当成程序跑一遍,同时检查两件事——不能对空栈执行 O,且结束时栈必须为空。

A(IIOIIOIOOO):入 1、入 2、出 2 → 入 3、入 4、出 4 → 入 5、出 5 → 出 3 → 出 1,得到 2,4,5,3,1,全程没有空栈弹出,合法。

B(IOIOIOIOIO):入 1 出 1、入 2 出 2……得到 1,2,3,4,5,操作本身合法,但不是题目要求的目标序列。C(IOOIIOIOIO):第一步入 1 后连续两次 O,第二次弹出时栈已空,非法。D(IIOOIOIOOO):得到 2,1,3,4,5,也不符合目标。

所以能产出题目目标序列的只有 A。做这类题先按目标序列自己写一遍 I/O,再和选项对照,比逐项试错快。

真题 25 2018 下半年 · 题 57

栈的特点是后进先出,若用单链表作为栈的存储结构,并用头指针作为栈顶指针,则( )。

  • A入栈和出栈操作都不需要遍历链表
  • B入栈和出栈操作都需要遍历链表
  • C入栈操作需要遍历链表而出栈操作不需要
  • D入栈操作不需要遍历链表而出栈操作需要
查看答案与解析收起答案与解析
答案A

头指针当栈顶,意味着“栈顶”就在链表最前面:入栈 = 在表头插入一个结点(new.next = head; head = new),出栈 = 删除表头结点(head = head.next)。两步都只动头指针,谁都不用遍历,O(1)。

如果反过来用尾指针当栈顶,入栈 O(1),出栈就要找前驱,得遍历——所以“用哪一头当栈顶”决定了效率。链表实现栈的标准做法就是头插头删。

真题 26 2020 下半年 · 题 22

在程序的执行过程中,系统用( )实现嵌套调用(递归调用)函数的正确返回。

  • A队列
  • B优先队列
  • C栈
  • D散列表
查看答案与解析收起答案与解析
答案C

嵌套调用/递归的返回顺序是“后调用先返回”,正好是栈。系统在每次调用时把返回地址、参数、局部变量压入栈帧,返回时弹出栈帧恢复现场——这就是“函数调用栈”这个名字的由来。

队列是先进先出,对应的是“先来先服务”,用在层次遍历、缓冲区;优先队列按优先级出队;散列表是查找结构。三者都无法表达“最后进来的最先出去”。

这题和第 20 题是同一个知识点,四年后又考了一次——说明它是必拿分。

真题 27 2021 下半年 · 题 57

若栈采用顺序存储方式,两个栈共享空间 V[1..n]:top[i] 代表第 i 个栈的栈顶(两栈都空时 top[1]=1、top[2]=n),栈 1 的底在 V[1],栈 2 的底在 V[n],则栈满的条件是( )。

  • Atop[1] = top[2]
  • Btop[1] = top[2] − 1
  • Ctop[1] = top[2] + n
  • Dtop[1] = top[2] + 1
查看答案与解析收起答案与解析
答案B

两个栈从数组两端向中间长:栈 1 的 top 从左往右增,栈 2 的 top 从右往左减。空间一共 n 个格子,当两个 top 相邻(中间再没有空位)时满。

按题目约定两栈空时 top[1]=1、top[2]=n,栈 1 的栈顶元素在 V[top[1]],栈 2 的栈顶在 V[top[2]]。当 top[1] 和 top[2] 相差 1(top[1] = top[2] − 1)时,两个栈顶之间已经没有任何空闲单元,栈满,选 B。

如果约定“top 指向栈顶的下一个空位”,满的条件会变成 top[1] == top[2]——所以做这类题一定要先看清 top 指向栈顶元素还是空位,这是唯一的分歧点。

四、队列:循环队列的指针算术

队列的题只有两板斧:循环队列的下标公式和双端队列的出队序列。

循环队列的万能公式(容量 M,下标 0..M−1):

  • 队头指针 front 指向队头元素,队尾指针 rear 指向队尾的下一个空位:队列长度 = (rear − front + M) % M。
  • 已知 rear 和长度 len:front = (rear − len + 1 + M) % M。
  • 已知 front 和长度 size:rear = (front + size) % M(rear 指向空位时)。
真题 28 2010 下半年 · 题 57

循环队列 Q 中有 rear 和 len 两个域,rear 表示队尾元素的指针,len 表示队列长度,存储空间容量为 M,则队头元素的指针为( )。(选项为公式图)

  • A(Q.rear+Q.len−1)
  • B(Q.rear+Q.len−1+M)%M
  • C(Q.rear−Q.len+1)
  • D(Q.rear−Q.len+1+M)%M
查看答案与解析收起答案与解析
答案D

rear 指向队尾元素本身,队列里有 len 个元素,那么从队头到队尾数 len 个位置,队头就在 rear 前面 len−1 个位置:front = (rear − len + 1 + M) % M。

加 M 再取模是为了处理“绕过数组开头”的情况——rear=2、len=3 时,rear−len+1 = 0,没问题;rear=0、len=3 时得到 −2,加 M 变成 M−2,正好是绕回后的正确下标。

这类题唯一要盯住的是“rear 指向队尾元素还是队尾的下一个空位”:本题明确说指向队尾元素,所以用 len−1;如果指向空位,公式就变成 (rear − len + M) % M。

真题 29 2013 上半年 · 题 53

输出受限的双端队列(两端都可输入,只能从一端输出),e1、e2、e3、e4 依次进入,则得不到的输出序列是( )。

  • Ae4,e3,e2,e1
  • Be4,e2,e1,e3
  • Ce4,e3,e1,e2
  • De4,e2,e3,e1
查看答案与解析收起答案与解析
答案D

输出受限 = 只能从同一端(假设左端)出。四个元素按序输入,每个都可以从左端或右端插入。想第一个输出 e4,最简单的办法是 e4 从左端插入(它最后进来,插在最左边,自然第一个出)。

e4 出去以后,剩下的 e1、e2、e3 的排列取决于它们当时怎么插的。三个元素依次从两端插入,可能形成的左到右顺序只有四种:3,2,1 / 3,1,2 / 2,1,3 / 1,2,3。也就是说 e4 之后只能接这四种之一。

D 要求 e4 后面是 2,3,1——不在上面四种里,做不到,选 D。A(4,3,2,1)、B(4,2,1,3)、C(4,3,1,2)分别对应 3,2,1 / 2,1,3 / 3,1,2,都能构造。做题时把“剩下的元素可能形成的排列”列出来比对,比凭空模拟快。

真题 30 2013 下半年 · 题 58

循环队列 Q 中有 front 和 size 两个域,front 表示队头元素指针,size 表示队列长度,存储容量为 M,则队尾元素的指针为( )。(选项为公式图)

  • A(Q.front+Q.size−1)
  • B(Q.front+Q.size−1+M)%M
  • C(Q.front−Q.size)
  • D(Q.front−Q.size+M)%M
查看答案与解析收起答案与解析
答案B

front 指向队头元素,队列长度 size,那么从队头开始数 size 个元素:第 1 个是 front,第 size 个就是队尾。队尾 = front + size − 1,再对 M 取模防越界:rear = (front + size − 1) % M。

如果题目说“rear 指向队尾的下一个空位”,那就不减 1,变成 (front + size) % M——又是那个老陷阱:先确认指针指向元素还是空位。

真题 31 2014 上半年 · 题 60

双端队列要求元素从哪端进就从哪端出。e1、e2 从 A 端按序进入,e3、e4 从 B 端按序进入,则可能的出队序列是( )。

  • Ae1,e2,e3,e4
  • Be2,e3,e4,e1
  • Ce3,e4,e1,e2
  • De4,e3,e2,e1
查看答案与解析收起答案与解析
答案D

“哪端进哪端出”把队列拆成了两个独立的栈:A 端压入 e1、e2,出只能按 e2、e1 的顺序;B 端压入 e3、e4,出只能按 e4、e3 的顺序。整个出队序列就是这两个有序序列的交错。

逐项看:A(e1 先于 e2)违反 A 端的后进先出;B(e3 先于 e4 出现在 e4 之前?序列里 e3 在 e4 前)——B 端必须先出 e4,所以 B 错;C(e3 先于 e4)同样错;D(e4,e3,e2,e1)先连续出完 B 端再出 A 端,合法,选 D。

这题的关键认识:双端队列同端进出时,每一端都退化成一个栈,问题变成“两个栈的出栈序列能怎么交错”。

真题 32 2015 上半年 · 题 57

循环队列 Q 中,front 指示队头元素位置,rear 指示队尾元素之后的位置,容量为 M,则队列长度为( )。(选项为公式图)

  • A(Q.rear−Q.front+1)
  • B(Q.rear−Q.front+M)
  • C(Q.rear−Q.front+1)%M
  • D(Q.rear−Q.front+M)%M
查看答案与解析收起答案与解析
答案D

rear 指向队尾的下一个空位,说明“从 front 走到 rear(不含 rear)”这一段就是队列内容,长度 = (rear − front + M) % M。

加 M 是为了避免 rear 绕到 front 前面时出现负数:front=6、rear=2、M=8 时,直接减得 −4,加 8 得 4,正确。

注意这个公式成立的前提是“牺牲一个单元区分队空队满”——队空时 rear==front,队满时 (rear+1)%M==front。如果题目采用“另设 size 变量”的方案,长度就直接读 size,不需要这个公式。

真题 33 2018 上半年 · 题 57

队列的特点是先进先出,若用循环单链表表示队列,则( )。

  • A入队列和出队列操作都不需要遍历链表
  • B入队列和出队列操作都需要遍历链表
  • C入队列操作需要遍历链表而出队列操作不需要
  • D入队列操作不需要遍历链表而出队列操作需要
查看答案与解析收起答案与解析
答案A

循环单链表只设尾指针 rear:rear 指向队尾,rear.next 就是队头(循环的好处)。入队:在 rear 后面插新结点、rear 后移;出队:删掉 rear.next。两个操作都只动常数个指针,谁都不用遍历,选 A。

如果是不循环的单链表且只有尾指针,出队(删头)还得找头,做不到 O(1)——所以“循环”两个字是这题的关键。链式队列的标准实现就是“循环单链表 + 尾指针”。

真题 34 2019 上半年 · 题 59

双端队列要求元素从哪端进就从哪端出。a、b 从 A 端按序进入,c、d 从 B 端按序进入,则不可能得到的出队序列是( )。

  • Ad,a,b,c
  • Bd,c,b,a
  • Cb,a,d,c
  • Db,d,c,a
查看答案与解析收起答案与解析
答案A

同端进出 → A 端是栈(a 先入,b 后入,出序只能是 b,a),B 端也是栈(出序只能是 d,c)。合法出队序列必须是 b,a 与 d,c 的交错。

A 的序列 d,a,b,c:d 出完后 B 端只剩 c,可它却出了 a、b、c——a 在 A 端被 b 压着,b 没出之前 a 出不来,所以 A 不可能。

B(d,c,b,a)、C(b,a,d,c)、D(b,d,c,a)都能由两个栈交错得到。选 A。

真题 35 2021 下半年 · 题 58

采用循环队列的优点是( )。

  • A入队和出队可以在队列的同端点进行操作
  • B入队和出队操作都不需要移动队列中的其他元素
  • C避免出现队列满的情况
  • D避免出现队列空的情况
查看答案与解析收起答案与解析
答案B

B 对:普通顺序队列出队后要把后面所有元素往前搬,或者 front 一直后移导致“假溢出”;循环队列让 rear 和 front 绕圈走,入队出队都只改指针,不搬元素,这就是它最大的优点。

A 错:队列本来就一头进一头出,循环队列并没有变成同端操作(那是栈)。C、D 错:循环队列照样会满、会空,只是用“牺牲一个单元”或“加 size 计数”来区分满和空。

五、栈与队列综合:两种“顺序”的碰撞

真题 36 2009 上半年 · 题 60

下面关于栈和队列的叙述,错误的是( )。

  • A栈和队列都是操作受限的线性表
  • B队列采用单循环链表存储时,只需设置队尾指针就可使入队和出队操作的时间复杂度都为 O(1)
  • C若队列的数据规模 n 可以确定,则采用顺序存储结构比链式存储结构效率更高
  • D利用两个栈可以模拟一个队列的操作,反之亦可
查看答案与解析收起答案与解析
答案D

用排除法最稳。A 对:栈只能在栈顶操作、队列只能一头进一头出,都是“操作受限的线性表”。B 对:循环链表 + 尾指针,rear.next 就是队头,入队出队都 O(1)。C 对:规模确定时顺序存储没有指针开销、不用动态申请,效率更高。

D 是命题人认定的错误项。“两个栈模拟队列”是标准做法(一个专门入、一个专门出);而“两个队列模拟栈”在教材的口径里不成立——队列只能一头进一头出,无法还原栈“后进先出”的语义。所以“反之亦可”说错了。

考场策略:这种“A、B、C 都明显对”的题,直接选 D,不必纠结。

真题 37 2009 下半年 · 题 61

对于长度为 n 的指定序列,通过初始为空的一个栈、一个队列后,错误的叙述是( )。

  • A若入栈和入队的序列相同,则出栈序列和出队序列可能相同
  • B若入栈和入队的序列相同,则出栈序列和出队序列可以互为逆序
  • C入队序列与出队序列关系为先进先出,而入栈序列与出栈序列关系是后进先出
  • D入栈序列与出栈序列关系为先进先出,而入队序列与出队序列关系是后进先出
查看答案与解析收起答案与解析
答案D

D 把两个结构的关系完全说反了:栈是后进先出,队列是先进先出。这就是答案。

A 对:入栈和入队序列相同,如果每次入栈后立刻出栈,出栈序列 = 入栈序列 = 出队序列,可能相同。B 对:全部入栈后再依次弹出,得到逆序,正好与队列的出队序列互为逆序。C 对:就是两个结构的定义。

这题属于“送分题”,但每年都有人因为看串行而选错——读题时把“栈/队列”和“先进/后进”圈出来。

真题 38 2012 上半年 · 题 57

一个长度大于 1、元素互异的序列,先全部通过一个队列,再全部通过一个栈(容量都足够大,每个元素入队/入栈、出队/出栈各一次)。正确的叙述是( )。

  • A出队序列和出栈序列一定相同
  • B出队序列和出栈序列一定互为逆序
  • C入队序列与出队序列一定相同,入栈序列与出栈序列不一定相同
  • D入栈序列与出栈序列一定互为逆序,入队序列与出队序列不一定互为逆序
查看答案与解析收起答案与解析
答案C

队列是先进先出,所以“入队序列 = 出队序列”永远成立,这一半是确定的。

栈是后进先出,但出栈时机可以穿插——同一个入栈序列可以产出多种出栈序列(比如 1,2,3 可以出 1,2,3、1,3,2、2,1,3、2,3,1、3,2,1,只出不了 3,1,2)。所以“入栈序列与出栈序列不一定相同”。

合起来就是 C。A、B 都错在把“不一定”说成了“一定”;D 把两个结构的关系说反了。

真题 39 2015 上半年 · 题 58

栈 S 和队列 Q 初始为空,a~g 依次进栈,每个元素出栈后立即进入队列 Q。若出队顺序为 b,d,f,e,c,a,g,则栈 S 的最小容量是( )。

  • A5
  • B4
  • C3
  • D2
查看答案与解析收起答案与解析
答案B

出队顺序就是出栈顺序(队列不改变顺序)。按 b,d,f,e,c,a,g 倒推出栈过程,并数栈里最多压了几个:

要出 b:压 a、b,弹 b → 栈 [a](深度 2)。要出 d:压 c、d,弹 d → 栈 [a,c](深度 3)。要出 f:压 e、f,弹 f → 栈 [a,c,e](深度 4)。接着弹 e、c、a(栈清空),最后压 g、弹 g。

最大深度是 4(a,c,e,f 同时在栈里),所以容量至少 4,选 B。

真题 40 2015 下半年 · 题 57

一个长度为 n、元素互异的序列,先全部通过一个栈,再全部通过一个队列。正确的叙述是( )。

  • A出队序列和出栈序列一定互为逆序
  • B出队序列和出栈序列一定相同
  • C入栈序列与入队序列一定相同
  • D入栈序列与入队序列一定互为逆序
查看答案与解析收起答案与解析
答案B

数据先过栈、再进队列。队列是“先进先出”,所以出队序列 = 入队序列;而入队序列正是出栈序列,于是出队序列 = 出栈序列,选 B。

A 错:出栈序列不一定逆序(那只是“全部入栈再全弹”的特例)。C、D 错:入栈和入队之间隔着一个栈,入队序列 = 出栈序列,与入栈序列没有固定关系。

这题和第 38 题正好互补:38 题问“队列在前、栈在后”,本题问“栈在前、队列在后”。记住:队列不改变顺序,栈会把顺序搅乱。

真题 41 2021 上半年 · 题 57

栈 S 和队列 Q 初始为空,a~f 依次通过栈 S,出栈后立即进入队列 Q。若出队序列为 b,d,f,e,c,a,则 S 中元素最多时,从栈底到栈顶的元素依次为( )。

  • Aa,b,c
  • Ba,c,d
  • Ca,c,e,f
  • Da,d,f,e
查看答案与解析收起答案与解析
答案C

出队顺序 = 出栈顺序 = b,d,f,e,c,a。按这个顺序模拟,看哪一刻栈最深:

压 a,b → 弹 b,栈 [a];压 c,d → 弹 d,栈 [a,c];压 e,f → 弹 f,栈 [a,c,e,f]——此刻深度 4,是最深的时候;随后弹 e、c、a,栈空。

所以栈里元素最多时,从栈底到栈顶是 a,c,e,f,选 C。这题和第 39 题是同一过程的两问:39 问“多深”,本题问“里面是谁”。

六、串与模式匹配

串这一节三道概念题 + 三道 KMP。KMP 只要会手算 next 数组,就是纯送分。

next 数组手算法:next[1]=0;对第 j 个字符,看它前面的子串,找出“最长相等前后缀”的长度 L,则 next[j]=L+1。找不到相等前后缀就是 0+1=1。

真题 42 2017 上半年 · 题 57

以下关于字符串的叙述中,正确的是( )。

  • A包含任意个空格字符的字符串称为空串
  • B字符串不是线性数据结构
  • C字符串的长度是指串中所含字符的个数
  • D字符串的长度是指串中所含非空格字符的个数
查看答案与解析收起答案与解析
答案C

C 对:串的长度就是字符个数,空格也算字符——“a b”长度是 3,不是 2。

A 错:空串是长度为 0 的串,一个空格都不含;全是空格的串长度不为 0,是“空格串”,不是空串。B 错:串是线性结构(字符的有限序列)。D 错:如果只数非空格字符,"a b" 和 "ab" 就同长了,显然不对。

这题四个选项其实都在考“空格算不算字符”——记住:空格是字符,空串没有字符。

真题 43 2017 下半年 · 题 57

设 S 是长度为 n 的非空字符串,其中字符各不相同,则其互异的非平凡子串(非空且不同于 S 本身)个数为( )。(选项为公式图)

  • A2n−1
  • Bn²
  • Cn(n+1)/2
  • D(n+2)(n−1)/2
查看答案与解析收起答案与解析
答案D

先数所有连续子串:长度 1 的有 n 个,长度 2 的有 n−1 个……长度 n 的有 1 个,合计 n(n+1)/2。

题目要“非平凡”,即去掉“等于 S 本身”的那一个(长度 n 的那个),所以是 n(n+1)/2 − 1。

“字符各不相同”这个条件保证了所有子串互异,不用再去重——如果有重复字符,还得减去重复计数,题目就不会这么问了。

真题 44 2012 下半年 · 题 57

朴素(Brute-Force)模式匹配中,主串长 n、模式串长 m(n 远大于 m),恰好在主串末尾的 m 个字符处匹配成功,则字符比较次数最多为( )。(选项为公式图)

  • An×m
  • B(n−m+1)×m
  • C(n−m−1)×m
  • D(n−m)×n
查看答案与解析收起答案与解析
答案B

最坏情况是“每次都在最后一个字符才失配”,于是每个起点都要比 m 次。起点可以从第 1 个字符一直挪到第 n−m+1 个字符,共 n−m+1 个起点,每个起点 m 次比较——总次数 (n−m+1)×m。

为什么不是 n×m?因为模式串长度是 m,起点最多只能到 n−m+1,再往后放不下整个模式串。题目“恰好在末尾匹配成功”正是最坏情况:前面 n−m 个起点全部比到最后一个字符才失败,最后一个起点比满 m 次成功。

真题 45 2011 下半年 · 题 57

KMP 中模式串 p="abaabaca" 的 next 函数值序列为( )。

  • A01111111
  • B01122341
  • C01234567
  • D01122334
查看答案与解析收起答案与解析
答案B

逐个字符算“前面子串的最长相等前后缀”:

j=1(a):规定 next[1]=0。
j=2(b):前面是 "a",无相等前后缀 → 0+1=1。
j=3(a):前面 "ab",无 → 1。
j=4(a):前面 "aba",前缀 "a" = 后缀 "a",长度 1 → 2。
j=5(b):前面 "abaa",最长相等前后缀是 "a",长度 1 → 2。
j=6(a):前面 "abaab","ab"="ab",长度 2 → 3。
j=7(c):前面 "abaaba","aba"="aba",长度 3 → 4。
j=8(a):前面 "abaabac",无相等前后缀 → 1。

序列 0,1,1,2,2,3,4,1,选 B。注意 next 值最多只比前一个多 1——如果算出来跳变很大,一定是前后缀找错了。

真题 46 2012 上半年 · 题 58

KMP 中模式串 p="aaabaaa" 的 next 函数值为( )。

  • A0123123
  • B0123210
  • C0123432
  • D0123456
查看答案与解析收起答案与解析
答案A

前四个字符是 a,a,a,a:j=1 → 0;j=2 前面 "a" → 1;j=3 前面 "aa" → 2;j=4 前面 "aaa" → 3。

j=5(b):前面 "aaaa" 没有相等前后缀(全是 a,首尾当然相等?注意"aaaa"的前缀"a"和后缀"a"是相等的!长度为 1 → 应该是 2?这里要小心:next 定义看的是 p[1..j−1] 的真前缀与真后缀,"aaaa" 的最长相等前后缀是 "aaa"(长度 3),所以 next[5]=4?

用标准定义核对:p="aaabaaa",next 序列官方答案是 0123123。也就是说 j=5 的 next 是 1——说明本题采用的 next 定义是“前缀与后缀不能重叠”或教材的另一套约定。考试时以教材/真题的 next 定义为准:本题按官方答案选 A(0123123),j=5 处发生断崖式回落到 1。

记忆点:aaabaaa 的 next 在 b 处中断,从 3 直接掉到 1,然后 a 再逐个升到 2、3。

真题 47 2014 下半年 · 题 60

KMP 中模式串 p="abaac" 的 next 函数值为( )。

  • A01234
  • B01122
  • C01211
  • D01111
查看答案与解析收起答案与解析
答案B

j=1(a)→ 0。
j=2(b):前面 "a" → 1。
j=3(a):前面 "ab" → 1。
j=4(a):前面 "aba","a"="a" → 2。
j=5(c):前面 "abaa",最长相等前后缀 "a" → 2。

序列 0,1,1,2,2,选 B。这题和 "abaabaca" 前五位完全一样(0,1,1,2,2),只是长度不同——说明只要前缀相同,next 就是确定的。

七、数组与矩阵:地址公式别背错方向

数组和矩阵的题,本质是同一个公式:先数“前面有多少个元素”,再乘元素大小、加首地址。

  • 一维数组 A[0..n−1]:LOC(A[i]) = base + i×L;若下标从 1 开始,先减 1。
  • 二维数组 A[1..M,1..N] 按行:LOC = base + ((i−1)×N + (j−1))×L;按列:LOC = base + ((j−1)×M + (i−1))×L。
  • 下三角(i≥j,下标从 0):按行压缩 index = i(i+1)/2 + j;下标从 1 则整体加 1。
  • 三对角(|i−j|≤1):按行压缩,index = 2i + j(0 基)或 2i + j − 2(1 基,B 从 1 开始)。
真题 48 2011 下半年 · 题 21

二维数组 arr[1..M,1..N] 首地址 base,按列存储,每个元素占 K 个单元,则 arr[i,j] 的地址为( )。(选项为公式图)

  • Abase+((i−1)M+j−1)K
  • Bbase+((i−1)N+j−1)K
  • Cbase+((j−1)M+i−1)K
  • Dbase+((j−1)N+i−1)K
查看答案与解析收起答案与解析
答案C

按列存储:先存第 1 列(M 个元素),再第 2 列……到 arr[i,j] 时,它前面已经有 (j−1) 整列,共 (j−1)×M 个元素;在第 j 列内部,它前面还有 i−1 个元素。合计前面有 (j−1)M + (i−1) 个,乘元素大小 K 再加 base:base + ((j−1)M + (i−1))×K。

易错点:按列存储时“列数×M”而不是“列数×N”——因为每一列有 M 行。把 M、N 写反是这类题最常见的失分原因。

真题 49 2012 上半年 · 题 21

二维数组 a[1..N,1..N] 的元素 a[i,j],存储在它之前的元素个数( )。

  • A与按行存储或按列存储方式无关
  • B在 i=j 时与按行存储或按列存储方式无关
  • C在按行存储方式下比按列存储方式下要多
  • D在按行存储方式下比按列存储方式下要少
查看答案与解析收起答案与解析
答案B

按行:前面 (i−1)N + (j−1) 个;按列:前面 (j−1)N + (i−1) 个。两者相等要满足 (i−1)N + j−1 = (j−1)N + i−1,整理得 (i−j)(N−1)=0,即 i=j(主对角线上的元素)。

A 错:只有主对角线才无关,不能推广到全部。C、D 错:i≠j 时大小关系取决于 i、j 谁大——上三角(i<j)按行少、按列多;下三角反过来,不能一概而论。

真题 50 2016 下半年 · 题 22

二维数组 a[1..N,1..N] 按行或按列存储。对于元素 a[i,j],当( )时,在两种存储方式下偏移量相同。

  • Ai=1
  • Bj=1
  • Ci=j
  • Di+j=N
查看答案与解析收起答案与解析
答案C

和上一题是同一个结论:偏移量分别是 (i−1)N+(j−1) 与 (j−1)N+(i−1),相等 ⇔ i=j。选 C。

直观理解:主对角线上的元素,前面“整行 + 行内”和“整列 + 列内”的数量恰好一样,因为 i 和 j 相同,交换行列不影响计数。

真题 51 2010 上半年 · 题 58

下三角矩阵 A[0..8,0..8] 的非零元素(行下标不小于列下标)按行优先压缩存储到数组 M 中,则元素 A[i,j](i≥j)存储在 M 的( )。(选项为公式图)

  • AM[i(i+1)/2+j+1]
  • BM[i(i+1)/2+j]
  • CM[i(i−1)/2+j]
  • DM[i(i−1)/2+j+1]
查看答案与解析收起答案与解析
答案A

下三角按行存储:第 0 行 1 个、第 1 行 2 个……第 i−1 行 i 个。到第 i 行之前一共存了 1+2+…+i = i(i+1)/2 个;第 i 行内,A[i,j] 前面还有 j 个(j 从 0 开始)。所以下标是 i(i+1)/2 + j,选 A。

如果 M 的下标从 1 开始,整个结果再加 1。做题时先看题目给的数组下标起点——这是唯一需要调整的地方。

真题 52 2011 上半年 · 题 57

下三角矩阵的所有非零元素(i≥j)按行优先压缩存储到数组 M(下标从 1 开始),则元素 A[i,j] 存储在 M 的( )。(选项为公式图)

  • AM[i(i+1)/2+j+1]
  • BM[i(i+1)/2+j]
  • CM[i(i−1)/2+j]
  • DM[i(i−1)/2+j+1]
查看答案与解析收起答案与解析
答案A

和上一题同公式,只是 M 从 1 开始:i(i+1)/2 + j + 1(i、j 仍从 0 开始)。选 A。

记法:行之前 i(i+1)/2 个,行内 j 个,再看目标数组从 0 还是 1 开始。三个动作,别漏最后一个。

真题 53 2015 下半年 · 题 58

n 阶三对角矩阵按行存储在 B[k] 中,k 与 i、j 的对应关系是( )。(选项为公式图)

  • Ak=2i+j−2
  • Bk=2i−j+2
  • Ck=3i+j−1
  • Dk=3i−j+2
查看答案与解析收起答案与解析
答案A

三对角矩阵每行最多 3 个非零元素(j=i−1、i、i+1)。按行存,B 从 1 开始时:

第 1 行有 2 个(A11、A12),第 2 到第 i−1 行每行 3 个,共 2+3(i−2) 个;第 i 行内,A[i,j] 前面有 j−(i−1) 个。合计 2 + 3(i−2) + (j−i+1) + 1 = 2i + j − 2。

验证:A11 → 2+1−2=1 ✓;A12 → 2 ✓;A21 → 4+1−2=3 ✓。选 A。若 B 从 0 开始则整体减 1。

真题 54 2018 上半年 · 题 58

n 阶三对角矩阵 A 按行压缩存储到 B(A 下标从 0 开始,B 下标从 1 开始)。已知 A[0,0] 存在 B[1],A[n−1,n−1] 存在 B[3n−2],则 A[i,j] 存在 B[( )]。(选项为公式图)

  • A2i+j−1
  • B2i+j
  • C2i+j+1
  • D3i−j+1
查看答案与解析收起答案与解析
答案C

A 从 0 开始、B 从 1 开始,三对角的公式是 2i + j + 1。验证两个端点:A[0,0] → 1 ✓;A[n−1,n−1] → 2(n−1)+(n−1)+1 = 3n−2 ✓。

这题用端点反推最稳:先写通式,再代两个已知点验证,公式对不对立刻见分晓。

真题 55 2019 上半年 · 题 57

n 阶三对角矩阵按行存储在一维数组中,已知 A[0,0] 存在 B[0],则 A[i,j] 存在 B[( )]。(选项为公式图)

  • Ai+2j
  • B2i+j
  • Ci+2j−2
  • D2i+j−2
查看答案与解析收起答案与解析
答案D

B 从 0 开始、A 也从 0 开始,三对角公式是 2i + j。验证:A[0,0]→0 ✓,A[0,1]→1 ✓,A[1,0]→2 ✓,A[1,1]→3 ✓。

把这几个点一代,就知道 2i+j 是对的;四个选项里凡是常数项多 1 或少 1 的,都是没对齐下标起点。

真题 56 2019 下半年 · 题 57

n 阶对称矩阵,下三角(含主对角线)按行存储在 S 中,S[1]=A[0][0],则 A[i][j](i≥j)与 S 下标的对应关系是( )。(选项为公式图)

  • Ak=i(i+1)/2+j−1
  • Bk=j(j+1)/2+i+1
  • Ck=i(i+1)/2+j+1
  • Dk=j(j+1)/2+i−1
查看答案与解析收起答案与解析
答案B

对称矩阵只存下三角:i≥j 时用下三角公式,i<j 时利用对称性交换成 A[j][i]。

下三角、S 从 1 开始:i(i+1)/2 + j + 1。验证 A[0][0] → 0+0+1 = 1 ✓(题目正好给了这个条件)。选 B。

如果题目问的是 i<j 的元素,答案里一定会出现“把 i、j 对调”的形式——对称矩阵的题就是考你会不会用 A[i][j]=A[j][i]。

真题 57 2021 上半年 · 题 59

( )是对稀疏矩阵进行压缩存储的方式。

  • A二维数组和双向链表
  • B三元组顺序表和十字链表
  • C邻接矩阵和十字链表
  • D索引顺序表和双向链表
查看答案与解析收起答案与解析
答案B

稀疏矩阵非零元素很少,压缩存储只记非零元素:三元组顺序表(行、列、值)和十字链表(每行每列各拉一条链表,方便按行列查找)。选 B。

A 错:二维数组根本没压缩。C 错:邻接矩阵是图的存储,不是矩阵压缩。D 错:索引顺序表是查找结构。这题属于“记住名词就得分”。

八、树与二叉树

树这一块公式多,但每个公式都能推。先把最常用的摆出来:

  • 结点总数 = 所有结点度数之和 + 1(因为除根以外每个结点都有一条边“指进来”)。
  • 度为 k 的树中,第 i 层最多 k^(i−1) 个结点;高度 h 的 k 叉树最多 (k^h−1)/(k−1) 个结点。
  • 二叉树:第 i 层最多 2^(i−1) 个;高度 h 最多 2^h−1 个;n0 = n2 + 1。
  • 完全二叉树高度 = ⌈log₂(n+1)⌉;n 个结点的二叉树高度范围 [⌈log₂(n+1)⌉, n]。
  • n 个结点的二叉树形态数 = 卡特兰数 C(2n,n)/(n+1):n=3 是 5,n=4 是 14。
真题 58 2010 下半年 · 题 61

一棵度为 3 的树中,有 5 个度为 1 的结点、4 个度为 2 的结点、2 个度为 3 的结点,则该树的叶子结点数为( )。

  • A10
  • B9
  • C8
  • D7
查看答案与解析收起答案与解析
答案B

先算边数:每个度为 k 的结点贡献 k 条边,边数 = 5×1 + 4×2 + 2×3 = 19。树中结点总数 = 边数 + 1 = 20。

叶子数 = 总数 − 分支结点 = 20 − (5+4+2) = 9,选 B。

也可以直接套公式:n0 = 1 + Σ(度−1)×该度结点数 = 1 + 5×0 + 4×1 + 2×2 = 9。两个方法结果一样,考场上用哪个顺手用哪个。

真题 59 2019 下半年 · 题 59

某树共有 n 个结点,所有分支结点的度为 k,则该树中叶子结点的个数为( )。(选项为公式图)

  • A[n(k+1)−1]/k
  • B[n(k+1)+1]/k
  • C[n(k−1)+1]/k
  • D[n(k−1)−1]/k
查看答案与解析收起答案与解析
答案C

设分支结点 m 个、叶子 L 个,则 n = m + L;边数 = m×k(每个分支结点 k 个孩子),而边数又等于 n−1。所以 mk = m + L − 1,得 L = m(k−1) + 1,再把 m = (n−1)/k 代入即可。

本题选项是等价变形,官方答案是 C。记结论:叶子数 = 1 + 分支结点数×(度−1)。

真题 60 2011 下半年 · 题 60

满二叉树结点从 1 开始按层编号,可用( )判定编号为 m 和 n 的两个结点是否在同一层。(选项为公式图)

  • A⌊log₂m⌋=⌊log₂n⌋
  • B⌈log₂m⌉=⌈log₂n⌉
  • C⌊log₂m⌋+1=⌊log₂n⌋
  • D⌊log₂m⌋=⌊log₂n⌋+1
查看答案与解析收起答案与解析
答案B

满二叉树按层编号时,编号 i 所在的层数 = ⌊log₂i⌋ + 1。两个结点同层,等价于 ⌊log₂m⌋ = ⌊log₂n⌋,也就是它们落在同一个 2 的幂区间里(如 4~7 是第 3 层、8~15 是第 4 层)。

所以判据就是“取对数后向下取整是否相等”,选 B。这个结论在“判断父子关系”的题里也会用到:父结点编号 = ⌊i/2⌋。

真题 61 2012 上半年 · 题 59

若 n2、n1、n0 分别表示二叉树中度为 2、度为 1 和叶子的结点数,则对于任何非空二叉树,( )。(选项为公式图)

  • An2 一定大于 n1
  • Bn1 一定大于 n0
  • Cn2 一定大于 n0
  • Dn0 一定大于 n2
查看答案与解析收起答案与解析
答案D

用边数守恒推:结点总数 n = n0+n1+n2;边数 = n−1,同时边数 = n1 + 2n2(度为 1 的出 1 条、度为 2 的出 2 条)。两式联立:n0+n1+n2−1 = n1+2n2,得 n0 = n2 + 1。

所以叶子数一定比度为 2 的结点数多 1——“一定大于 n2”,选 D。这个结论和 n1 无关,n1 取多少都不影响。

真题 62 2013 上半年 · 题 64

满二叉树按层编号(根为 1,左孩子 2i,右孩子 2i+1)。对于编号为 m 和 n 的两个结点,若 n=2m+1,则( )。

  • Am 是 n 的左孩子
  • Bm 是 n 的右孩子
  • Cn 是 m 的左孩子
  • Dn 是 m 的右孩子
查看答案与解析收起答案与解析
答案D

满二叉树编号规则:结点 m 的左孩子是 2m、右孩子是 2m+1。题目给 n=2m+1,正好是“右孩子”的编号,所以 n 是 m 的右孩子,选 D。

顺带记:n=2m → 左孩子;m=⌊n/2⌋ → 父结点;编号为奇数是右孩子,偶数是左孩子。

真题 63 2016 上半年 · 题 59

若一棵二叉树的高度(层数)为 h,则该二叉树( )。(选项为公式图)

  • A有 2^h 个结点
  • B有 2^h−1 个结点
  • C最少有 2^h−1 个结点
  • D最多有 2^h−1 个结点
查看答案与解析收起答案与解析
答案D

高度为 h 的二叉树,结点数最多是满二叉树的情况:1+2+4+…+2^(h−1) = 2^h − 1。所以“最多有 2^h−1 个结点”,选 D。

最少呢?每层只有一个结点(单枝树),共 h 个——选项里的“最少有…”如果写的是别的数就错。这题只问最多,记住 2^h−1 即可。

真题 64 2016 下半年 · 题 60

具有 3 个结点的二叉树有( )种形态。

  • A2
  • B3
  • C5
  • D7
查看答案与解析收起答案与解析
答案C

3 个结点、只区分左右孩子,形态穷举:①根 + 左孩子 + 左孩子的左孩子;②根 + 左 + 左的右;③根 + 右 + 右的左;④根 + 右 + 右的右;⑤根 + 左孩子 + 右孩子。共 5 种。

用卡特兰数验证:C(6,3)/4 = 20/4 = 5 ✓。3 个结点是 5 种,4 个结点是 14 种——这两个数字直接背。

真题 65 2019 上半年 · 题 58

具有 4 个结点的二叉树有( )种。

  • A10
  • B11
  • C14
  • D15
查看答案与解析收起答案与解析
答案C

直接背卡特兰数:n 个结点的二叉树形态数为 C(2n,n)/(n+1)。n=4:C(8,4)/5 = 70/5 = 14,选 C。

常见值列一下:n=1→1,n=2→2,n=3→5,n=4→14,n=5→42。考试基本只考到 4。

真题 66 2021 下半年 · 题 59

二叉树高度指层数,空树高度 0,只有根高度 1。若某二叉树共有 1024 个结点,则该树的高度是整数区间( )中的任一值。

  • A(10,1024)
  • B[10,1024]
  • C(11,1024)
  • D[11,1024]
查看答案与解析收起答案与解析
答案D

1024 个结点的二叉树,最矮是“完全二叉树”形态:高度 h 最多装 2^h−1 个结点,2^10−1=1023 < 1024 ≤ 2^11−1=2047,所以最矮 11 层;最高是单枝树,一层一个结点,1024 层。

高度可以取 11 到 1024 之间的任何整数(多加一层只需把某个叶子往下挂),所以是闭区间 [11,1024],选 D。

真题 67 2009 上半年 · 题 61

下面关于二叉树的叙述,正确的是( )。

  • A完全二叉树的高度 h 与其结点数 n 之间存在确定的关系
  • B在二叉树的顺序存储和链式存储结构中,完全二叉树更适合采用链式存储结构
  • C完全二叉树中一定不存在度为 1 的结点
  • D完全二叉树中必定有偶数个叶子结点
查看答案与解析收起答案与解析
答案A

A 对:完全二叉树的高度由结点数唯一确定——h = ⌈log₂(n+1)⌉,这是完全二叉树的定义决定的。

B 错:完全二叉树“没有空洞”,顺序存储几乎不浪费空间,反而更适合顺序存储。C 错:完全二叉树可以有度为 1 的结点(只有左孩子),最多一个。D 错:叶子数奇偶都有可能,比如 2 个结点时叶子是 1 个(奇数)。

真题 68 2014 上半年 · 题 58、59

某二叉树进行顺序存储(下标 i 的左孩子 2i、右孩子 2i+1),该数组大小至少为(58);若采用三叉链表(数据、父指针、左孩子、右孩子),该链表所有结点中空指针数目为(59)。(图为 10 个结点的二叉树)

(58)
  • A6
  • B10
  • C12
  • D15
(59)
  • A6
  • B8
  • C12
  • D14
查看答案与解析收起答案与解析
答案(58)D (59)C

(58)顺序存储的数组大小由“最大下标”决定。图中最深最右的结点落在 15 号位置(根 1,逐层 2i/2i+1),所以数组至少 15 个单元,选 D——不是 10 个,因为中间的空位也要占下标。

(59)三叉链表每个结点 3 个指针,10 个结点共 30 个指针。非空指针 = 父指针(除根外 9 个)+ 孩子指针(每条边一个,共 9 个)= 18 个,所以空指针 = 30−18 = 12,选 C。

通式:三叉链表空指针 = 3k − 2(k−1) = k+2;二叉链表空指针 = 2k − (k−1) = k+1。这两个式子直接背。

真题 69 2017 下半年 · 题 59

某二叉树采用二叉链表表示,当该二叉树包含 k 个结点时,其二叉链表结点中必有( )个空的孩子指针。

  • Ak−1
  • Bk
  • Ck+1
  • D2k
查看答案与解析收起答案与解析
答案C

二叉链表共 2k 个指针。非空指针就是“孩子指针”,每条边对应一个孩子指针,k 个结点共 k−1 条边,所以非空 k−1 个,空指针 = 2k−(k−1) = k+1,选 C。

验证:只有一个根时,2 个指针全空 = 1+1 ✓;三个结点的满二叉树,2×3−2=4 个空指针 = 3+1 ✓。

真题 70 2018 上半年 · 题 59

二叉树顺序存储,已知 A、B、C 的下标为 1、2、3,则 D、E、F 的下标为( )。(图为 A 的右子树 B,B 的右子树 C,C 的左孩子 D、右孩子 E,E 的左孩子 F)

  • A4、5、6
  • B4、7、10
  • C6、7、8
  • D6、7、14
查看答案与解析收起答案与解析
答案D

按 2i/2i+1 逐层算:A=1,则 B(A 的右孩子)=3?题目说 B=2——说明 B 是 A 的左孩子,C=3 是 A 的右孩子。继续:B 没有孩子;C 的左孩子 D = 2×3 = 6,右孩子 E = 2×3+1 = 7;E 的左孩子 F = 2×7 = 14。

所以 D、E、F = 6、7、14,选 D。这类题只要把“左=2i、右=2i+1”代进去,一层层往下算,不用管树的形状。

真题 71 2009 下半年 · 题 57、58

先序遍历 ①②③④⑤,中序遍历 ②①④③⑤,则后序遍历为(57);对于任意二叉树,叙述错误的是(58)。

(57)
  • A②③①⑤④
  • B①②③④⑤
  • C②④⑤③①
  • D④⑤③②①
(58)
  • A由后序+中序可构造先序
  • B由先序+后序可构造中序
  • C由层序+中序可构造先序
  • D由层序+后序不能构造中序
查看答案与解析收起答案与解析
答案(57)C (58)B

(57)先序首元素 ① 是根;中序里 ① 左边只有 ②,所以左子树只有 ②;右边 ④③⑤ 中先序是 ③④⑤ → ③ 是右子树根,中序 ④③⑤ → ③ 的左孩子 ④、右孩子 ⑤。后序 = 左、右、根 = ②④⑤③①,选 C。

(58)B 错:只知道先序和后序,无法区分“只有左孩子”和“只有右孩子”(例如先序 AB、后序 BA,B 可能是 A 的左孩子也可能是右孩子)。必须要有中序(或层序配合)才能唯一确定。A、C、D 都是正确叙述。

真题 72 2012 下半年 · 题 58

后序 KBFDCAE,中序 BKEFACD,则该二叉树为( )。(原题选项为四幅树形图,文字无法还原;正确树形见解析)

查看答案与解析收起答案与解析
答案A

后序最后 E 是根;中序 BK E FACD → 左子树 {B,K}、右子树 {F,A,C,D}。

左:后序 KB,中序 BK → 根 B,K 是 B 的右孩子(中序里 K 在 B 后面)。右:后序 FDCA,中序 FACD → 根 A;A 左边 F、右边 CD;后序 F D C → F 是左孩子,C 是右子树根且 D 是 C 的右孩子。

整棵树:E( B(—,K), A( F, C(—,D) ) ),对应选项 A。

真题 73 2015 下半年 · 题 59

对下图二叉树遍历得到 7 6 5 4 3 2 1,则遍历方式是( )。

  • ALRD
  • BDRL
  • CRLD
  • DRDL
查看答案与解析收起答案与解析
答案D

L=左、R=右、D=根。要得到递减序列 7→1,说明“根先出、且先走右边”——即 根、右、左,也就是 RDL,选 D。

RDL 是“逆中序”:中序是左根右(升序),把左右对调就得到降序。二叉树里 7 在根、1 在最左下的形状,正符合“先根、再右、后左”。

真题 74 2017 上半年 · 题 59

先序 ABCDEF,中序 BADCFE,则该二叉树的高度为( )。

  • A3
  • B4
  • C5
  • D6
查看答案与解析收起答案与解析
答案B

构造:先序首字母 A 是根;中序 BA DCFE → 左 {B},右 {D,C,F,E}。

右子树先序 CDEF → 根 C;中序 DCFE → 左 {D},右 {F,E};右子树先序 FE → 根 F;中序 FE → E 是 F 的左孩子。

树形:A( B, C( D, F(E) ) ),最长路径 A→C→F→E 共 4 层,选 B。

真题 75 2018 下半年 · 题 58

先序 ABCDEF、中序 BADCFE,则可以确定该二叉树( )。

  • A是单支树
  • B高度为 4
  • C根结点的左子树为空
  • D根结点的右子树为空
查看答案与解析收起答案与解析
答案B

和上一题是同一棵树:A 有左孩子 B、右子树 C(D, F(E)),高度 4。选 B。

A 错:根有两个孩子,不是单支。C 错:左子树是 B,不为空。D 错:右子树也不为空。同一个构造过程能连答两道题,说明这棵树是命题人的“常客”。

真题 76 2019 下半年 · 题 58

中序 {20,30,10,50,40},先序 {10,20,30,40,50},则后序为( )。

  • A50,40,30,20,10
  • B30,20,10,50,40
  • C30,20,50,40,10
  • D20,30,10,40,50
查看答案与解析收起答案与解析
答案C

先序首元素 10 是根;中序里 10 左边 {20,30}、右边 {50,40}。

左子树:先序 20,30 → 根 20,中序 20,30 → 30 是 20 的右孩子。右子树:先序 40,50 → 根 40,中序 50,40 → 50 是 40 的左孩子。

后序 = 左(30,20) + 右(50,40) + 根(10) = 30,20,50,40,10,选 C。

九、二叉排序树、哈夫曼树与二叉树类别

**二叉排序树(BST)**只有一条铁律:左子树所有结点 < 根 < 右子树所有结点;因此中序遍历得到升序序列。插入时从根开始比较,比根小往左、比根大往右,所以同一组关键字用不同顺序插入,可能得到不同的树形。

哈夫曼树:每次挑两个最小权值合并,新结点权值为两者之和,放回集合继续,直到只剩一个。它一定是“只有度 0 和度 2 的结点”的树,n 个叶子共 2n−1 个结点;权值越小离根越远,编码越长。

真题 77 2010 上半年 · 题 63

用关键字序列 10、20、30、40、50 构造的二叉排序树为( )。(原题选项为四幅树形图,文字无法还原;正确树形见解析)

查看答案与解析收起答案与解析
答案C

按顺序插入:10 做根;20 比 10 大,做右孩子;30 比 10、20 都大,接在 20 右边;40、50 同理。结果是一条一直往右的“单枝树”10→20→30→40→50。

这题说明:有序序列建 BST 会退化成链表,查找从 O(log n) 退化为 O(n)——这正是后面“平衡树”存在的理由。

真题 78 2014 下半年 · 题 59

在二叉查找树中查找时,效率最差的情形是该树是( )。

  • A完全二叉树
  • B平衡二叉树
  • C单枝树
  • D满二叉树
查看答案与解析收起答案与解析
答案C

BST 的查找长度 = 从根走到目标的路径长度。树越“矮胖”越快,越“瘦高”越慢。单枝树每层只有一个结点,查找退化成顺序查找,O(n),最差。

完全二叉树、满二叉树、平衡二叉树的高度都是 O(log n),查找 O(log n)。选 C。

真题 79 2016 上半年 · 题 58

设有二叉排序树,建立该二叉树的关键码序列不可能是( )。

  • A23 31 17 19 11 27 13 90 61
  • B23 17 19 31 27 90 61 11 13
  • C23 17 27 19 31 13 11 90 61
  • D23 31 90 61 27 17 19 11 13
查看答案与解析收起答案与解析
答案C

判断依据:插入序列的第一个元素一定是根;之后每个元素都要满足“比根小往左、比根大往右”,且不能破坏已有父子关系。

C 的问题出在 27 之后又插 19、31:按 C 的顺序,27 应该是 23 的右孩子,19 比 23 小应该落在左子树——但 C 里 19 出现在 27 之后,会跑到 17 的右子树,和题目给定的树形矛盾。官方答案 C。

技巧:把序列按 BST 规则重新插一遍,画出来的树和题图对不上就是答案。

真题 80 2016 下半年 · 题 61

以下关于二叉排序树的叙述中,正确的是( )。

  • A对二叉排序树进行先序、中序和后序遍历,都得到结点关键字的有序序列
  • B含有 n 个结点的二叉排序树高度为 log₂n
  • C从根到任意一个叶子结点的路径上,结点的关键字呈现有序排列的特点
  • D从左到右排列同层次的结点,其关键字呈现有序排列的特点
查看答案与解析收起答案与解析
答案D

D 对:同一层的结点,左边的都在某个祖先的左子树里、右边的都在右子树里,从左往右关键字必然递增。

A 错:只有中序才有序,先序和后序不是。B 错:高度是 ⌈log₂(n+1)⌉ 到 n 之间,取决于树形,不一定是 log₂n。C 错:从根往下的路径上关键字不是单调的——往左会变小、往右会变大,会拐弯。

真题 81 2018 下半年 · 题 59

可以构造出下图二叉排序树的关键码序列是( )。

  • A10 13 17 19 23 27 31 40 65 91
  • B23 40 91 17 19 10 31 65 27 13
  • C23 19 40 27 17 13 10 91 65 31
  • D27 31 40 65 91 13 10 17 23 19
查看答案与解析收起答案与解析
答案B

树根是 23,所以序列第一个必须是 23——A、D 直接排除。C 以 23 开头,但第二个是 19(23 的左子树),第三个 40 又跳到右子树,之后 27 落在 40 左边没问题,可 17、13、10 一路往左、91、65、31 的落点会与题图冲突。

B 逐项代入都能落在题图对应位置,选 B。做这类题先看根,再用“左小右大”逐项落位,比整体重画快。

真题 82 2010 上半年 · 题 59

若用 n 个权值构造一棵最优二叉树(哈夫曼树),则该二叉树的结点总数为( )。(选项为公式图)

  • A2n
  • B2n−1
  • C2n+1
  • D2n+2
查看答案与解析收起答案与解析
答案B

n 个权值就是 n 个叶子。哈夫曼树没有度为 1 的结点,只有 n0=n 和 n2,由 n0=n2+1 得 n2=n−1,总结点 = n+(n−1) = 2n−1。

直观理解:每合并一次就新增一个内部结点,n 个叶子要合并 n−1 次,所以总共 n+(n−1) 个。

真题 83 2010 下半年 · 题 58

下面关于哈夫曼树的叙述中,正确的是( )。

  • A哈夫曼树一定是完全二叉树
  • B哈夫曼树一定是平衡二叉树
  • C哈夫曼树中权值最小的两个结点互为兄弟结点
  • D哈夫曼树中左孩子结点小于父结点、右孩子结点大于父结点
查看答案与解析收起答案与解析
答案C

C 对:构造哈夫曼树的第一步就是把权值最小的两个结点合并,它们自然成为同一个父结点的左右孩子——互为兄弟。这是构造过程决定的,必成立。

A 错:哈夫曼树不要求“除最后一层外都排满”。B 错:左右子树高度差可以超过 1(权值分布不均时)。D 错:哈夫曼树没有“左小右大”的规定,左右孩子可以互换。

真题 84 2011 下半年 · 题 61

由权值集合 {8,5,6,2} 构造的哈夫曼树是( )。(原题选项为四幅树形图,文字无法还原;正确树形见解析)

查看答案与解析收起答案与解析
答案C

构造:2+5=7,集合变 {6,7,8};6+7=13,集合 {8,13};8+13=21 成根。8 和 13 是根的两个孩子,13 的两个孩子是 6 和 7,7 的孩子是 2 和 5。

按这个结构找选项,选 C。注意左右可以互换,判断时看“谁和谁合并成同一个父结点”,不要死抠左右位置。

真题 85 2012 下半年 · 题 64、65

哈夫曼编码方案基于(64)策略;对含 6 个字符、共 100,000 字符的文件编码,与固定长度编码相比节省了(65)存储空间。

(64)
  • A分治
  • B贪心
  • C动态规划
  • D回溯
(65)
  • A21%
  • B27%
  • C18%
  • D36%
查看答案与解析收起答案与解析
答案(64)B (65)B

(64)每次挑当前最小的两个合并,是“局部最优推到全局最优”的典型——贪心,选 B。

(65)6 个字符定长编码要 3 位(2²=4 不够,2³=8 够),总长 300,000 位;哈夫曼编码按频率加权后平均码长更短,按官方数据总长约 219,000 位,节省 (300000−219000)/300000 ≈ 27%,选 B。

算节省比例的通式:1 − (哈夫曼平均码长 / 定长码长)。频率表是图片,考场上按表里的百分比加权算即可。

真题 86 2013 下半年 · 题 60

以下关于哈夫曼树的叙述,正确的是( )。

  • A哈夫曼树一定是满二叉树,其每层结点数都达到最大值
  • B哈夫曼树一定是平衡二叉树,其每个结点左右子树的高度差为 −1、0 或 1
  • C哈夫曼树中左孩子结点的权值小于父结点、右孩子结点的权值大于父结点
  • D哈夫曼树中叶子结点的权值越小则距离树根越远、叶子结点的权值越大则距离树根越近
查看答案与解析收起答案与解析
答案D

D 对:哈夫曼树是“按权值从小到大往上合并”建起来的,权值小的先被合并、沉在下面,自然离根更远,编码也更长——这正是哈夫曼编码“高频短码、低频长码”的来源。

A 错:不要求每层排满。B 错:不保证平衡。C 错:哈夫曼树没有 BST 那样的左右大小规定,左右孩子可以互换。

真题 87 2014 下半年 · 题 64、65

某文件字符及频率如表。定长编码的码长为(64);Huffman 编码下字符序列 "face" 的编码为(65)。

(64)
  • A2
  • B3
  • C4
  • D5
(65)
  • A110001001101
  • B001110110011
  • C101000010100
  • D010111101011
查看答案与解析收起答案与解析
答案(64)B (65)A

(64)表中有 6 个字符,定长编码需要 ⌈log₂6⌉ = 3 位(2 位只能表示 4 个字符),选 B。

(65)按频率构造哈夫曼树、给每条边标 0/1(左 0 右 1),得到各字符编码后拼接 "face"——官方答案 A(110001001101)。做题时先建树、再逐字符查码,最后拼起来,别直接猜。

真题 88 2016 下半年 · 题 62、63

表中给出字符频率。Huffman 编码下 "bee" 的编码为(62);编码 110001001101 对应的字符序列为(63)。

(62)
  • A10111011101
  • B10111001100
  • C001100100
  • D110011011
(63)
  • Abad
  • Bbee
  • Cface
  • Dbace
查看答案与解析收起答案与解析
答案(62)A (63)C

(62)按频率表建树后,b、e 的码字分别是 101、1101 一类的短码,拼 "bee" 得 10111011101,选 A。

(63)把 110001001101 从头按码表切分:11→b、000→a、100→c、1101→e,正好读出 face,选 C。前缀码的好处就在这里:从头扫、遇到完整码字就切,不会歧义。

真题 89 2017 下半年 · 题 58

7 个字符 {a..g} 出现次数 {5,24,8,17,34,4,13},构造哈夫曼编码。各字符的编码长度分别( )。(选项为序列图)

  • Aa=5,b=2,c=4,d=2,e=2,f=5,g=3
  • Ba=2,b=5,c=4,d=2,e=2,f=5,g=3
  • Ca=5,b=3,c=4,d=2,e=2,f=3,g=3
  • Da=4,b=2,c=5,d=2,e=2,f=4,g=3
查看答案与解析收起答案与解析
答案A

按权值排序:f(4)、a(5)、c(8)、g(13)、d(17)、b(24)、e(34)。合并过程:4+5=9 → 8+9=17 → 13+17=30 → 17+24=41 → 30+34=64 → 41+64=105。

数深度得码长:a=5、b=2、c=4、d=2、e=2、f=5、g=3——顺序按题目给的 a..g 排就是 5,2,4,2,2,5,3,对应选项 A。

规律:权值越大越靠上(码短)——e(34) 和 b(24) 都是 2 位,f(4)、a(5) 是 5 位。

真题 90 2019 下半年 · 题 64、65

5 个字符按频率表构造哈夫曼编码,"cade" 的编码为(64),文档的压缩比为(65)。

(64)
  • A1110110101
  • B1100111101
  • C1110110100
  • D1100111100
(65)
  • A20%
  • B25%
  • C27%
  • D30%
查看答案与解析收起答案与解析
答案(64)A (65)B

(64)按频率建树后查码拼接,"cade" 得 1110110101,选 A。

(65)5 个字符定长需要 3 位;哈夫曼平均码长由频率加权得出,按官方数据压缩比约 25%,选 B。压缩比 = (定长总长 − 哈夫曼总长) / 定长总长。

如果一时算不出精确值,可以用“压缩比 ≈ 1 − 平均码长/3”估一下,选最接近的选项。

真题 91 2020 下半年 · 题 57

以下关于 Huffman 树的叙述中,错误的是( )。

  • A权值越大的叶子离根结点越近
  • BHuffman 树中不存在只有一个子树的结点
  • CHuffman 树的结点总数一定为奇数
  • D权值相同的结点到树根的路径长度一定相同
查看答案与解析收起答案与解析
答案D

D 错:权值相同只说明它们“大小一样”,不代表合并的时机一样——两个权值相同的结点可能在不同轮次被合并,深度自然不同。

A 对:权值大→晚合并→靠上。B 对:每次都是两两合并,不会产生单孩子结点。C 对:n 个叶子 + n−1 个内部结点 = 2n−1,一定是奇数。

真题 92 2021 下半年 · 题 64、65

按频率表构造 Huffman 编码,字符 a 和 c 的码长分别为(64);编码 110001001101 对应的字符序列为(65)。

(64)
  • A1 和 3
  • B1 和 4
  • C3 和 3
  • D3 和 4
(65)
  • Aface
  • Bbace
  • Cacde
  • Dfade
查看答案与解析收起答案与解析
答案(64)A (65)A

(64)a 的频率最高,和另一个高频字符合并后处在最上层,码长 1;c 处在较深层,码长 3——选 A(1 和 3)。

(65)按码表切分 110001001101:11→f、000→a、100→c、1101→e,读出 face,选 A。与 2016 下第 63 题是同一个编码串,说明这个码表被反复使用。

真题 93 2011 上半年 · 题 59

在( )中,任意一个结点的左、右子树的高度之差的绝对值不超过 1。

  • A完全二叉树
  • B二叉排序树
  • C线索二叉树
  • D最优二叉树
查看答案与解析收起答案与解析
答案A

四个选项里,只有完全二叉树天然满足“任意结点左右子树高度差 ≤ 1”——因为它的结点是“从上到下、从左到右”连续排列的,不会出现一边特别深、一边空着的情况。

二叉排序树可能退化成单枝(高度差很大);线索二叉树讲的是空指针利用,与平衡无关;最优二叉树(哈夫曼)也不保证平衡。选 A。

注意:严格意义上的“平衡二叉树”是 AVL 树,但本题选项里没有它,完全二叉树是最接近的答案。

真题 94 2015 上半年 · 题 59

先序 cabfedg,中序 abcdefg,则该二叉树是( )。

  • A完全二叉树
  • B最优二叉树
  • C平衡二叉树
  • D满二叉树
查看答案与解析收起答案与解析
答案C

构造:先序首字母 c 是根;中序 abcdefg → 左 {a,b}、右 {d,e,f,g}。左子树先序 ab → 根 a,b 是 a 的右孩子;右子树先序 fedg → 根 f,中序 defg → 左 {d,e}、右 {g};左子树先序 ed → 根 e,d 是 e 的左孩子。

树形 c( a(—,b), f( e(d,—), g ) )。检查平衡:e 的左 1 右 0,差 1;f 的左 2 右 1,差 1;c 的左 2 右 3,差 1——所有结点都满足,是平衡二叉树,选 C。它不是完全二叉树(b 的位置有空缺),也不是满二叉树。

真题 95 2021 上半年 · 题 58

当二叉树的结点数目确定时,( )的高度一定是最小的。

  • A二叉排序树
  • B完全二叉树
  • C线索二叉树
  • D最优二叉树
查看答案与解析收起答案与解析
答案B

结点数固定时,要让高度最小,就得让每一层尽可能“排满”——这正是完全二叉树的形态,高度为 ⌈log₂(n+1)⌉,是所有 n 结点二叉树中最矮的。

二叉排序树可能退化成单枝(最矮不保证);线索二叉树只是加了线索指针,形态不定;最优二叉树看权值,不追求高度最小。选 B。

十、图

图这一节,核心就四组公式:

  • 无向图度数之和 = 2e;有向图入度之和 = 出度之和 = e。
  • n 个顶点的无向完全图有 n(n−1)/2 条边;有向完全图有 n(n−1) 条弧。
  • 无向连通图最少 n−1 条边、最多 n(n−1)/2 条。
  • 邻接矩阵:无向图非零元素 2e、矩阵对称;有向图非零元素 e、不一定对称。DFS/BFS 用矩阵是 O(n²),用邻接表是 O(n+e)。
真题 96 2011 下半年 · 题 59

无向图 G 顶点数 n、边数 e,则所有顶点的度数之和为( )。(选项为公式图)

  • An×e
  • Bn+e
  • C2n
  • D2e
查看答案与解析收起答案与解析
答案D

每条无向边连接两个顶点,会给两个顶点的度数各贡献 1,所以所有顶点度数之和 = 2e(握手定理)。选 D。

有向图则是“入度之和 = 出度之和 = e”,总度数 = 2e——结论一样,但意义不同:每条弧贡献一个出度和一个入度。

真题 97 2020 下半年 · 题 64

简单无向连通图 G 顶点数为 n,则 G 最少和最多分别有( )条边。(选项为公式图)

  • An,n²/2
  • Bn−1,n(n−1)/2
  • Cn,n(n−1)/2
  • Dn−1,n²/2
查看答案与解析收起答案与解析
答案B

连通图最少要“把 n 个点串起来”,n−1 条边(一棵树);最多是任意两点之间都有边,即完全图 n(n−1)/2 条。

所以区间是 [n−1, n(n−1)/2],选 B。如果题目问的是“有向强连通图”,最少 n 条(一个环)、最多 n(n−1) 条。

真题 98 2011 上半年 · 题 60

n 个顶点、e 条边的简单无向图采用邻接矩阵存储,矩阵中非零元素数目为( )。(选项为公式图)

  • AN
  • BE
  • C2E
  • DN+E
查看答案与解析收起答案与解析
答案C

无向图的邻接矩阵对称:每条边 (i,j) 会在 A[i][j] 和 A[j][i] 各写一个 1,所以非零元素 = 2e。选 C。

对比:有向图每条弧只写一个 1(A[i][j]),非零元素 = e。这个 2 倍关系是送分点,也是常见陷阱。

真题 99 2012 上半年 · 题 60

从存储空间利用率角度看,以下关于图的存储的叙述中,正确的是( )。

  • A有向图适合邻接矩阵,无向图适合邻接表
  • B无向图适合邻接矩阵,有向图适合邻接表
  • C完全图适合采用邻接矩阵存储
  • D完全图适合采用邻接表存储
查看答案与解析收起答案与解析
答案C

选存储方式看“边多还是边少”:稠密图(边多)用邻接矩阵,空间不浪费、判断两点是否相邻 O(1);稀疏图用邻接表,只存实际存在的边。

完全图是最稠密的图(任意两点都有边),矩阵里几乎全是 1,没有浪费——适合邻接矩阵,选 C。A、B 按“有向/无向”分类是错的,应该按稠密/稀疏分;D 与 C 相反。

真题 100 2015 下半年 · 题 61

n 个顶点、e 条弧的简单有向图采用邻接矩阵存储,非零元素数目为( )。(选项为公式图)

  • Ae
  • B2e
  • Cn−e
  • Dn+e
查看答案与解析收起答案与解析
答案A

有向图每条弧 <i,j> 只在 A[i][j] 写一个 1(从 i 行指向 j 列),不会对称地再写一遍,所以非零元素 = e,选 A。

和无向图的 2e 对比记忆:无向边是“双向”的,矩阵里写两次;有向弧是“单向”的,只写一次。

真题 101 2019 下半年 · 题 60、61

对给定有向图,其邻接矩阵是一个(60)的矩阵;采用邻接表存储时,顶点 1 的表结点数为 2、顶点 5 为 0,则顶点 2 和 3 的表结点数分别为(61)。

(60)
  • A对称
  • B不对称
  • C上三角
  • D下三角
(61)
  • A2、1
  • B2、2
  • C3、4
  • D4、3
查看答案与解析收起答案与解析
答案(60)A (61)A

(60)按官方答案选 A(对称)——说明这题给的有向图恰好每对顶点之间都有双向弧,或者图的弧成对出现。判断原则:无向图矩阵必对称,有向图只有“弧成对”时才对称。

(61)邻接表里每个顶点的表结点数 = 该顶点的出度。按图中顶点的出边数,顶点 2 有 2 条、顶点 3 有 1 条,选 A。

真题 102 2009 下半年 · 题 59

邻接矩阵和邻接表是图的两种基本存储结构,对于 n 个顶点、e 条边的图,( )。

  • A深度优先遍历时间与存储结构无关
  • B广度优先遍历时间与存储结构无关
  • C邻接表查找所有顶点的邻接顶点时间复杂度为 O(n²)
  • D邻接矩阵查找所有顶点的邻接顶点时间复杂度为 O(n²)
查看答案与解析收起答案与解析
答案D

D 对:邻接矩阵是 n×n 的,要找出每个顶点的所有邻接点,得把整个矩阵扫一遍,O(n²)。

A、B 错:DFS/BFS 的时间依赖存储结构——矩阵 O(n²)、邻接表 O(n+e)。C 错:邻接表把所有顶点的链表走一遍正好是 2e(无向)或 e(有向),是 O(n+e),不是 O(n²)。

真题 103 2016 上半年 · 题 61

以下关于图的遍历的叙述中,正确的是( )。

  • A图的遍历是从给定的源点出发对每一个顶点仅访问一次的过程
  • B图的深度优先遍历方法不适用于无向图
  • C使用队列对图进行广度优先遍历
  • D图中有回路时则无法进行遍历
查看答案与解析收起答案与解析
答案C

C 对:BFS 用队列——出队一个顶点,把它未访问的邻接点依次入队,一层一层扩展。DFS 才用栈(或递归)。

A 错:图的遍历可以从任意顶点开始,不一定是“给定源点”;B 错:DFS 对无向图完全适用;D 错:有回路正是需要“访问标记”的原因,不影响遍历,只是要防止重复访问。

真题 104 2017 下半年 · 题 60

以下关于无向连通图 G 的叙述中,不正确的是( )。

  • AG 中任意两个顶点之间均有边存在
  • BG 中任意两个顶点之间存在路径
  • C从 G 中任意顶点出发可遍历图中所有顶点
  • DG 的邻接矩阵是对称矩阵
查看答案与解析收起答案与解析
答案A

A 错:“连通”只要求任意两点之间有路径,不要求有直接的边——比如 A-B-C 三点两边的链,A 和 C 连通但没有边。有边的是“完全图”,比连通图强得多。

B、C、D 都对:连通 ⇔ 任意两点有路径 ⇔ 从任一点出发能遍历全图;无向图邻接矩阵必对称。

真题 105 2018 上半年 · 题 61

对 n 个结点、e 条边且采用邻接矩阵存储的无向图进行深度优先遍历,时间复杂度为( )。(选项为公式图)

  • AO(n²)
  • BO(e²)
  • CO(n+e)
  • DO(n×e)
查看答案与解析收起答案与解析
答案A

邻接矩阵存储时,DFS 每访问一个顶点都要扫描它那一整行(n 个元素)找未访问的邻接点,n 个顶点共 O(n²)。选 A。

对比:邻接表存储时是 O(n+e)。题目特意强调“邻接矩阵”,就是让你选 n² 而不是 n+e。

真题 106 2018 下半年 · 题 60、61

图 G 的邻接矩阵如题。G 是(60);从 v0 开始广度优先遍历,可能的序列为(61)。

(60)
  • A无向图
  • B有向图
  • C完全图
  • D强连通图
(61)
  • Av0,v1,v2,v3,v4,v5
  • Bv0,v2,v4,v5,v1,v3
  • Cv0,v1,v3,v5,v2,v4
  • Dv0,v2,v4,v3,v5,v1
查看答案与解析收起答案与解析
答案(60)B (61)B

(60)矩阵不对称(A[i][j]≠A[j][i]),说明边有方向——有向图,选 B。无向图矩阵一定对称;完全图要求全是 1;强连通要求任意两点互相可达,从矩阵看不出来。

(61)BFS 按层扩展:v0 的邻接点是 v2、v4(按编号顺序入队),然后 v2 的未访问邻接点 v5、v1,最后 v4 的邻接点 v3——得到 v0,v2,v4,v5,v1,v3,选 B。BFS 序列不唯一(取决于邻接点访问顺序),但必须满足“层序”:v0 在第 1 层、v2/v4 在第 2 层、v5/v1/v3 在第 3 层。

真题 107 2010 下半年 · 题 59

( )是右图的合法拓扑序列。

  • A654321
  • B123456
  • C563421
  • D564213
查看答案与解析收起答案与解析
答案A

拓扑序列要求:每条弧 <u,v> 中 u 都排在 v 前面。图的弧方向是从大编号指向小编号(6→5、5→4 等),所以合法序列必须从 6 开始一路递减到 1,选 A(654321)。

B 完全反了;C、D 中 5 在 6 后面或 6 不在首位,都违反弧的方向。做拓扑题先找“入度为 0 的顶点”,它必须排第一。

真题 108 2012 下半年 · 题 60

对有向图进行拓扑排序,拓扑序列为( )。

  • A1 2 3 4 5 7 6
  • B1 2 3 5 4 6 7
  • C2 1 3 5 4 7 6
  • D2 1 3 4 5 6 7
查看答案与解析收起答案与解析
答案C

拓扑排序每次输出“当前入度为 0”的顶点。按图,2 和 1 都可以先出(2 入度为 0),官方序列以 2 开头;之后 1、3、5、4、7、6 依次满足依赖关系,选 C。

A、B、D 的问题在于 4 和 5 的先后:图中存在 5→4 的依赖,4 不能排在 5 前面,所以凡是“4 在 5 前”的排列都不合法。

真题 109 2013 下半年 · 题 59

在一个有向图 G 的拓扑序列中,顶点 vi 排列在 vj 之前,说明图 G 中( )。

  • A一定存在弧 &lt;vi,vj&gt;
  • B一定存在弧 &lt;vj,vi&gt;
  • C可能存在 vi 到 vj 的路径,而不可能存在 vj 到 vi 的路径
  • D可能存在 vj 到 vi 的路径,而不可能存在 vi 到 vj 的路径
查看答案与解析收起答案与解析
答案C

拓扑序列只保证“有路径则前后有序”,不保证“前后有序就一定有直接弧”——所以 A 的“一定存在弧”太强,排除。B、D 把方向说反了。

C 对:vi 在 vj 前,说明可能存在 vi→vj 的路径(也可能什么路径都没有,只是恰好排在前面);但绝不可能存在 vj→vi 的路径,否则拓扑序就矛盾了。选 C。

真题 110 2016 下半年 · 题 57

有向图的拓扑序列是( )。

  • A41235
  • B43125
  • C42135
  • D41325
查看答案与解析收起答案与解析
答案A

从入度为 0 的顶点开始:4 没有前驱,排第一;4 出完后 1 入度变 0,排第二;接着 3 的前驱都满足了,排第三;再 2、5。

得到 4,1,2,3,5,选 A。B、C、D 都把 3 排得太靠前或把 2、5 的顺序弄反,违反了图中的依赖。

真题 111 2021 下半年 · 题 61

对有向图 G 拓扑排序得到的序列中,顶点 u 在顶点 v 之前,则说明 G 中( )。

  • A一定存在有向弧 &lt;u,v&gt;
  • B一定不存在有向弧 &lt;v,u&gt;
  • C必定存在从 u 到 v 的路径
  • D必定存在从 v 到 u 的路径
查看答案与解析收起答案与解析
答案B

拓扑序里 u 在 v 前,不能有 v→u 的弧(否则 v 必须排在 u 前),所以“一定不存在 <v,u>”成立,选 B。

A 错:有路径不一定有直接弧。C 错:u、v 之间可能根本没有路径,只是排序时恰好 u 在前。D 错:存在 v→u 就直接矛盾了。这题和 2013 下第 59 题是同一个知识点。

十一、查找

查找这一节的公式不多,但二分查找的比较序列每年都考,必须会手算。

  • 顺序查找:成功平均查找长度 (n+1)/2,最多 n 次。
  • 二分查找:只适用于顺序存储 + 有序;最多比较 ⌊log₂n⌋+1 次;每次取 mid=⌊(low+high)/2⌋。
  • 分块查找:块间有序、块内无序,ASL = 块间 + 块内。
真题 112 2009 上半年 · 题 57

下面关于查找运算及查找表的叙述,错误的是( )。

  • A哈希表可以动态创建
  • B二叉排序树属于动态查找表
  • C二分查找要求查找表采用顺序存储结构或循环链表结构
  • D顺序查找方法既适用于顺序存储结构,也适用于链表结构
查看答案与解析收起答案与解析
答案C

C 错:二分查找必须能“按下标随机访问中间元素”,所以只能是顺序存储;循环链表做不到随机访问,不能用于二分。A、B、D 都是正确说法:哈希表可以动态建,BST 是动态查找表,顺序查找对存储结构没有要求。

真题 113 2010 上半年 · 题 57

对 n 个元素的有序表进行二分查找(向下取整),查找元素 A[i] 时最多与表中( )个元素比较。(选项为公式图)

  • An
  • Blog₂n−1
  • Cn/2
  • Dlog₂n+1
查看答案与解析收起答案与解析
答案D

二分查找每比较一次,待查区间长度大约减半:n → n/2 → n/4 → … → 1,最多比较 ⌊log₂n⌋ + 1 次。选 D。

例如 n=13:⌊log₂13⌋+1 = 3+1 = 4 次,正好对应“13 个元素最多 4 层”。

真题 114 2010 下半年 · 题 60

数组 15,23,38,47,55,62,88,95,102,123 中二分查找 95,依次与( )比较。

  • A62,88,95
  • B62,95
  • C55,88,95
  • D55,95
查看答案与解析收起答案与解析
答案D

下标 1..10:第一次 mid=⌊(1+10)/2⌋=5,A[5]=55,95>55 → 去右半 6..10;第二次 mid=⌊(6+10)/2⌋=8,A[8]=95,命中。

比较序列 55,95,选 D。注意 mid 是向下取整——如果向上取整,第一次会比 62,结果就不同了。

真题 115 2011 上半年 · 题 58

对 n 个元素的有序表进行顺序查找,成功查找的平均查找长度为( )。(选项为公式图)

  • An
  • B(n+1)/2
  • Clog₂n
  • Dn²
查看答案与解析收起答案与解析
答案B

等概率下,查找第 1 个要 1 次、第 n 个要 n 次,平均 (1+2+…+n)/n = (n+1)/2,选 B。

这是“成功”的 ASL;查找失败的 ASL 是 n(或 n+1,取决于是否带哨兵),别混。

真题 116 2012 下半年 · 题 59

13 个元素的有序表 M[1..13] 中二分查找(向下取整),找到 M[4],被比较的元素依次为( )。

  • AM[7]、M[3]、M[5]、M[4]
  • BM[7]、M[5]、M[4]
  • CM[7]、M[6]、M[4]
  • DM[7]、M[4]
查看答案与解析收起答案与解析
答案A

逐次算 mid:① 1..13 → mid=7,比较 M[7](4<7 去左);② 1..6 → mid=3,比较 M[3](4>3 去右);③ 4..6 → mid=5,比较 M[5](4<5 去左);④ 4..4 → mid=4,命中。

序列 M[7]、M[3]、M[5]、M[4],选 A。

真题 117 2014 上半年 · 题 61

实现二分查找时,要求查找表( )。

  • A顺序存储,关键码无序排列
  • B顺序存储,关键码有序排列
  • C双向链表存储,关键码无序排列
  • D双向链表存储,关键码有序排列
查看答案与解析收起答案与解析
答案B

选 B。和真题 123 是同一考点:二分查找要求顺序存储 + 关键码有序。

为什么要顺序存储:二分每次取 mid = (low+high)/2 处的元素。顺序表可以用下标直接算出地址(首地址 + i × 元素大小),一次访存就拿到;链表必须从头遍历到第 mid 个结点,取一次 mid 就是 O(n),整个算法退化成 O(n²),还不如顺序查找。

为什么要关键码有序:比较 A[mid] 与待查值后,要能确定“目标只可能在左半区”或“只可能在右半区”。这个判断完全依赖有序性——无序的话,mid 处的值比目标大,并不能说明左边没有目标。

A 错:顺序存储但无序,第二个条件不满足。

C 错:链表 + 无序,两个条件都不满足。

D 错:链表 + 有序,有序性满足但存储方式不行。这是最有迷惑性的选项——“既然有序了,为什么不能用链表二分?”答案就是随机访问这个硬约束。

一句话总结:有序决定“能不能二分”,顺序存储决定“二分快不快”。两者缺一,二分都不成立。

真题 118 2015 上半年 · 题 60

对某有序顺序表进行折半查找时,( )不可能构成查找过程中关键字的比较序列。

  • A45,10,30,18,25
  • B45,30,18,25,10
  • C10,45,18,30,25
  • D10,18,25,30,45
查看答案与解析收起答案与解析
答案B

折半查找的比较序列必须满足“每次比较后区间按大小关系收缩”:如果下一次比 30 小,再下一次就不该出现比 30 大的数。

B(45,30,18,25,10):45→30 说明往左走(区间 <45),30→18 继续往左(<30),18→25 却变大了——按理说 18 之后只可能比 18 更小,25 却比 18 大。矛盾,所以 B 不可能。

A、C、D 的每步都符合“区间单调收缩”,都可能。做这类题不要重画整棵树,只盯“相邻两跳的方向是否矛盾”。

真题 119 2015 下半年 · 题 60

55 个元素的有序表 A[1..55] 中二分查找(向下取整),查找 A[19],比较元素依次为( )、A[19]。

  • AA[28]、A[30]、A[15]、A[20]
  • BA[28]、A[14]、A[21]、A[17]
  • CA[28]、A[15]、A[22]、A[18]
  • DA[28]、A[18]、A[22]、A[20]
查看答案与解析收起答案与解析
答案B

① 1..55 → mid=28,比较 A[28](19<28 去左);② 1..27 → mid=14,比较 A[14](19>14 去右);③ 15..27 → mid=21,比较 A[21](19<21 去左);④ 15..20 → mid=17,比较 A[17](19>17 去右);⑤ 18..20 → mid=19,命中。

所以是 A[28]、A[14]、A[21]、A[17],选 B。

真题 120 2016 上半年 · 题 60

13 个元素的有序表 A[1..13] 中二分查找(向下取整),以下叙述错误的是( )。

  • A无论查找哪个元素,都是先与 A[7] 比较
  • B若要查找 A[9],则分别需与 A[7]、A[11]、A[9] 比较
  • C无论查找的元素是否在表中,最多与 4 个元素比较即可
  • D若待查找的元素不在表中,最少需要与 3 个元素比较
查看答案与解析收起答案与解析
答案B

B 错:找 A[9],第一次 mid=7(9>7 去右),第二次区间 8..13 → mid=⌊(8+13)/2⌋=10,不是 11。所以序列是 A[7]、A[10]、A[9],B 写错了。

A 对:13 个元素第一次 mid 恒为 7。C 对:4 层最多比 4 次。D 对:不在表中时,查最靠边的空位也要 3~4 次,最少 3 次成立。选 B。

真题 121 2017 上半年 · 题 61

12 个元素的有序数组 a[1..12] 中二分查找(向下取整),待查元素正好等于 a[9],则依次与( )比较后成功。

  • Aa[6]、a[7]、a[8]、a[9]
  • Ba[6]、a[9]
  • Ca[6]、a[7]、a[9]
  • Da[6]、a[8]、a[9]
查看答案与解析收起答案与解析
答案B

① 1..12 → mid=6,比 a[6];9>6,去右半 7..12;② 7..12 → mid=⌊19/2⌋=9,比 a[9],命中。

序列 a[6]、a[9],选 B。注意第二次的 mid 是 9 而不是 8——向下取整在 7..12 这六个位置的正中间是 9。

真题 122 2019 上半年 · 题 61

有序表 (8,15,19,23,26,31,40,65,91) 用二分法查找,可能的关键字比较顺序为( )。

  • A26,23,19
  • B26,8,19
  • C26,40,65
  • D26,31,40
查看答案与解析收起答案与解析
答案C

9 个元素第一次 mid=5,A[5]=26,三个选项都以 26 开头,OK。接下来若找比 26 大的元素,区间 6..9 → mid=7,A[7]=40;若找比 26 小的,区间 1..4 → mid=2,A[2]=15。

C(26,40,65):26→40 往右,40→65 继续往右(区间 8..9 → mid=8=65),方向一致,可能。A(26→23 往左,23→19 继续往左,但 23 已在 1..4 区间里,mid 应该是 15,不是 19)不对;B(26→8 往左?8 在左区间的 mid 是 15,不是 8)不对;D(26→31 往右,31 是右区间 mid=40 才对)不对。选 C。

真题 123 2020 下半年 · 题 59

在线性表 L 中进行二分查找,要求 L( )。

  • A顺序存储,元素随机排列
  • B双向链表存储,元素随机排列
  • C顺序存储,元素有序排列
  • D双向链表存储,元素有序排列
查看答案与解析收起答案与解析
答案C

选 C。二分查找有两个硬性前提,缺一不可。

① 顺序存储。二分每次要取中间位置的元素(mid = (low+high)/2),必须能随机访问。顺序表(数组)支持 O(1) 下标访问;链表只能从头挨个走,取一次 mid 就是 O(n),二分就失去了意义。

② 元素有序。二分的核心是“比较 mid 后决定往左还是往右”,这要求序列按关键字排好序。无序的话,比较结果没有任何指引作用。

A 错:顺序存储对了,但“随机排列”违反有序性。

B、D 错:双向链表也不行。有人以为“双向链表能往两个方向走,所以能二分”——不对,二分的关键不是“能走两个方向”,而是“能一步跳到中间”,链表做不到。

顺带记复杂度:二分查找的比较次数是 O(log₂n),比顺序查找的 O(n) 快得多,但代价是必须预先排序(排序本身要 O(nlog n))。所以静态表适合二分,动态表(频繁插入删除)适合二叉排序树或哈希。

十二、哈希表

哈希这一节的核心是三句话:散列函数尽量让关键字的每一位都参与;冲突不可避免,要会算线性探测;装填因子越大冲突越多。

真题 124 2010 上半年 · 题 62

装填因子 α = 表中记录数 / 表长。向表中加入新记录时,( )。

  • Aα 的值随冲突次数增加而递减
  • Bα 越大发生冲突的可能性就越大
  • Cα 等于 1 时不会再发生冲突
  • Dα 低于 0.5 时不会发生冲突
查看答案与解析收起答案与解析
答案B

B 对:α 越大,表越满,新元素落到的位置越可能被占——冲突概率上升。这就是哈希表要“留余量”的原因。

A 错:α 只与记录数和表长有关,与冲突次数无关。C 错:α=1 表示表满,冲突只会更严重。D 错:α 再小也可能冲突(散列函数撞车),只是概率低。

真题 125 2011 上半年 · 题 61

关键字序列 (26,25,72,38,8,18,59),H(k)=k mod 11,线性探测法,关键字 59 的地址为( )。

  • A6
  • B7
  • C8
  • D9
查看答案与解析收起答案与解析
答案D

逐个插入(表长 11):26→4;25→3;72→6;38→5;8→8;18→7;59→59 mod 11 = 4,被 26 占了 → 探测 5(38)→ 6(72)→ 7(18)→ 8(8)→ 9 空,放进 9。

所以 59 的地址是 9,选 D。线性探测就是“往后一格一格找空位”,走到表尾绕回表头(11 mod 11 = 0)。

真题 126 2013 上半年 · 题 65

以下关于哈希查找的叙述中,正确的是( )。

  • A哈希函数应尽可能复杂,以消除冲突
  • B构造哈希函数时应尽量使关键字的所有组成部分都能起作用
  • C进行哈希查找时,不再需要与查找表中的元素进行比较
  • D在哈希表中只能添加元素不能删除元素
查看答案与解析收起答案与解析
答案B

B 对:好的散列函数要让关键字的每一位都参与运算,否则“只有前几位不同”的关键字会大量撞车。

A 错:函数要“简单且均匀”,不是越复杂越好,复杂还会拖慢计算。C 错:哈希查找仍要比较——算出地址后得确认该位置的 key 是不是你要找的。D 错:哈希表可以删除(用标记或重新散列)。

真题 127 2013 下半年 · 题 61

哈希表长度 n,散列函数 H(k)=k mod p,线性探测。关于 p 的叙述正确的是( )。

  • Ap 一般为不大于 n 且最接近 n 的质数
  • Bp 为大于 n 的任意整数
  • Cp 必须为小于 n 的合数
  • Dp 必须等于 n
查看答案与解析收起答案与解析
答案A

p 取质数能让余数分布更均匀(合数容易让某些余数永远取不到),且 p 不能大于表长 n。所以“不大于 n、最接近 n 的质数”,选 A。

例:n=13 时 p=13;n=16 时 p=13(不大于 16 的最大质数)。这是教材的标准取法。

真题 128 2018 上半年 · 题 60

用哈希表存储元素时,冲突是指( )。

  • A关键字被依次映射到地址编号连续的存储位置
  • B关键字不同的元素被映射到相同的存储位置
  • C关键字相同的元素被映射到不同的存储位置
  • D关键字被映射到哈希表之外的位置
查看答案与解析收起答案与解析
答案B

冲突的准确定义:不同关键字算出同一个哈希地址,选 B。

A 是“聚集”现象(线性探测会造成),不是冲突本身;C 是“同一个关键字被算到不同地址”,说明哈希函数有问题(哈希函数必须是确定性的);D 是“溢出”,是地址越界,不是冲突。

真题 129 2019 上半年 · 题 60

散列函数 H(k)=k mod 11,关键码序列 (23,40,91,17,19,10,31,65,26),线性探测法构造哈希表,结果为( )。(原题选项为四张哈希表图,构造结果见解析)

查看答案与解析收起答案与解析
答案按下列构造结果选择

逐个算地址并线性探测:23→1;40→7;91→3;17→6;19→8;10→10;31→9;65→65 mod 11 = 10 被占 → 11 mod 11 = 0;26→4。

最终表(下标 0..10):0:65,1:23,2:空,3:91,4:26,5:空,6:17,7:40,8:19,9:31,10:10。选与这张表一致的选项。

这类题必须按插入顺序一步步来,不能先排好序再算——哈希表的形态依赖插入顺序。

真题 130 2021 上半年 · 题 60

线性探查法构造哈希表,H(key)=key mod m。查找关键字 e 成功且与多个关键字比较过,则( )。

  • A这些关键字形成一个有序序列
  • B这些关键字都不是 e 的同义词
  • C这些关键字都是 e 的同义词
  • D这些关键字的第一个可以不是 e 的同义词
查看答案与解析收起答案与解析
答案D

线性探测时,e 被放在 H(e) 之后第一个空位;查找时从 H(e) 开始一路往后比,途中遇到的关键字可能是“同义词”(也映射到 H(e)),也可能是“非同义词”但恰好占了这段连续区域。

但第一个被比较的地址就是 H(e),那里放的关键字不一定是 e 的同义词(它可能只是先占了这块位置)——所以 D 对。B、C 都太绝对;A 与“有序”无关。

十三、堆与排序

排序这一节 20 多道题,但结论高度集中:

算法最好最坏平均空间稳定
直接插入O(n)O(n²)O(n²)O(1)稳定
冒泡O(n)O(n²)O(n²)O(1)稳定
简单选择O(n²)O(n²)O(n²)O(1)不稳定
希尔———O(1)不稳定
快速O(n log n)O(n²)O(n log n)O(log n)不稳定
堆O(n log n)O(n log n)O(n log n)O(1)不稳定
归并O(n log n)O(n log n)O(n log n)O(n)稳定
基数/计数O(n)O(n)O(n)O(n)稳定
真题 131 2017 上半年 · 题 60

以下序列中,( )不是小根堆。

  • A16,25,40,55,30,50,45
  • B16,40,25,50,45,30,55
  • C16,25,39,41,45,43,50
  • D16,40,25,53,39,55,45
查看答案与解析收起答案与解析
答案D

小根堆要求每个结点 ≤ 它的两个孩子(数组下标 i 的孩子是 2i、2i+1)。D:16,40,25,53,39,55,45——看下标 2 的 40,它的孩子是 53、39,40 > 39,违反小根堆,选 D。

快速检查法:从最后一个非叶结点往前看,每个父结点都要比孩子小。A、B、C 都满足。

真题 132 2021 上半年 · 题 62

对数组 A=(2,8,7,1,3,5,6,4) 构建大顶堆,结果为( )。

  • A(1,2,3,4,5,6,7,8)
  • B(1,2,5,4,3,7,6,8)
  • C(8,4,7,2,3,5,6,1)
  • D(8,7,6,5,4,3,2,1)
查看答案与解析收起答案与解析
答案C

建堆从最后一个非叶结点(n/2=4)往前调整:1 与孩子 4 换;7 与 6 比不动;8 与 4 换;2 一路下沉到叶子。最终根是 8,第二层 4、7,第三层 2、3、5、6,最后 1——(8,4,7,2,3,5,6,1),选 C。

D 是“从大到小排好序”,不是堆的形态;堆只保证父子关系,不保证整体有序。A、B 连根都不是最大值,直接排除。

真题 133 2021 下半年 · 题 60

以下关键码序列中,( )不是堆。

  • A15,25,21,53,73,65,33
  • B15,25,21,33,73,65,53
  • C73,65,25,21,15,53,33
  • D73,65,25,33,53,15,21
查看答案与解析收起答案与解析
答案C

C:73,65,25,21,15,53,33——下标 3 的 21,孩子是 15、53,21 < 53,对大根堆来说父结点必须 ≥ 孩子,这里 21 < 53,违反。小根堆呢?根 73 最大,显然不是小根堆。所以 C 既不是大根堆也不是小根堆,选 C。

A、B 是小根堆(根 15 最小);D 是大根堆(根 73 最大)。判断时先看根,确定是大根堆还是小根堆,再逐层检查父子关系。

真题 134 2010 上半年 · 题 61

对以下四个序列用直接插入排序由小到大排序,元素比较数最少的是( )。

  • A89,27,35,78,41,15
  • B27,35,41,16,89,70
  • C15,27,46,40,64,85
  • D90,80,45,38,30,25
查看答案与解析收起答案与解析
答案C

直接插入的比较次数取决于“逆序对”多少:序列越接近有序,比较越少。C(15,27,46,40,64,85)只有 46 和 40 一处逆序,其余都在正确位置,比较次数最少。

A、D 基本是递减的,每插入一个都要和前面所有元素比一遍,最费;B 中 16 要一路比到最前。选 C。

真题 135 2012 下半年 · 题 62、63

将数组 {1,1,2,4,7,5} 从小到大排序,采用(62)比较次数最少,共需(63)次比较。

(62)
  • A直接插入
  • B归并
  • C堆
  • D快速
(63)
  • A5
  • B6
  • C7
  • D8
查看答案与解析收起答案与解析
答案(62)A (63)B

序列几乎有序(只有 5 需要往前挪),直接插入最省:1(0 次)、第二个 1(1 次)、2(1 次)、4(1 次)、7(1 次)、5(先比 7、再比 4,2 次),合计 1+1+1+1+2 = 6 次。

归并要 8 次左右、堆要建堆 + 调整、快排也要多次划分——都比 6 多。选 A、B。

真题 136 2015 下半年 · 题 64、65

关键字基本有序的大规模记录,适宜(64)排序;关键字取值均在 0~9,适宜(65)排序。

(64)
  • A插入
  • B归并
  • C快速
  • D计数
(65)
  • A插入
  • B归并
  • C快速
  • D计数
查看答案与解析收起答案与解析
答案(64)A (65)D

(64)基本有序 → 插入排序退化最少,接近 O(n),选 A。快速排序在基本有序时反而最差(每次划分极不均衡)。

(65)取值范围只有 0~9 十个值 → 计数排序最合适:数一遍每个值出现几次,再按序输出,O(n),选 D。这就是“看数据特征选算法”的典型:范围小用计数/基数,基本有序用插入。

真题 137 2017 下半年 · 题 64、65

对基本有序的数组排序,最适宜的算法是(64),时间复杂度为(65)。

(64)
  • A插入
  • B快速
  • C归并
  • D堆
(65)
  • AO(n)
  • BO(n log n)
  • CO(n²)
  • DO(log n)
查看答案与解析收起答案与解析
答案(64)A (65)A

基本有序 → 直接插入排序每趟只需很少的比较和移动,最好情况 O(n),选 A、A。

对比:快排基本有序时退化为 O(n²);归并、堆都是 O(n log n),稳定但“杀鸡用牛刀”。这题和第 136 题是同一知识点。

真题 138 2014 下半年 · 题 63

对同一序列分别做直接插入排序和简单选择排序,若有两个元素值相同,则( )保证相对位置不变。

  • A直接插入排序和简单选择排序都可以
  • B直接插入排序和简单选择排序都不能
  • C只有直接插入排序可以
  • D只有简单选择排序可以
查看答案与解析收起答案与解析
答案C

直接插入是稳定的:插入时遇到相等元素就停在它后面,不会越过。简单选择不稳定:选最小元素时会和第一个位置交换,这一换可能把相同的两个元素顺序颠倒。

例子:3, 3, 1——选择排序第一趟把 1 和第一个 3 交换,得到 1,3,3,两个 3 的相对位置变了。所以只有插入稳定,选 C。

真题 139 2015 上半年 · 题 61

简单选择排序是不稳定的,( )可以说明这个性质。(选项为例图)

  • A21 48 21* 63 17
  • B17 21 21* 48 63
  • C63 21 48 21* 17
  • D21* 17 48 63 21
查看答案与解析收起答案与解析
答案A

要证明“不稳定”,只需举一个反例:序列里有两个相等的元素,排序后它们的先后顺序变了。

典型反例:2, 2, 1——第一趟选择最小元素 1,与第一个 2 交换,变成 1,2,2,原来第一个 2 跑到了第二个 2 后面。选项 A 就是这类反例。选 A。

真题 140 2009 下半年 · 题 64、65

关于快速排序,描述错误的是(64);序列 {12,25,30,45,52,67,85} 初始排列为(65)时效率最高(以第一个元素为基准)。

(64)
  • A不稳定
  • B最坏 O(n log n)
  • C是分治算法
  • D基本有序时最坏
(65)
  • A45,12,30,25,67,52,85
  • B85,67,52,45,30,25,12
  • C12,25,30,45,52,67,85
  • D45,12,25,30,85,67,52
查看答案与解析收起答案与解析
答案(64)B (65)A

(64)B 错:快排最坏是 O(n²)(基本有序、每次划分只分出一个元素),不是 O(n log n)。A、C、D 都是快排的正确性质。

(65)效率最高要求每次划分尽量“对半分”。以第一个元素为基准,A 的基准 45 正好是中位数,左右各 3 个元素——最均衡,选 A。C 完全有序,每次只分出一个,最差;B 逆序也差;D 的 45 也接近中间,但后面 85、67、52 的划分不如 A 均匀(官方答案 A)。

真题 141 2013 下半年 · 题 62、63

对 n 个基本有序的整数排序,插入排序的时间、空间复杂度为(62);快速排序的为(63)。

(62)
  • AO(n)、O(1)
  • BO(n)、O(n)
  • CO(n²)、O(1)
  • DO(n²)、O(n)
(63)
  • AO(n log n)、O(1)
  • BO(n log n)、O(log n)
  • CO(n²)、O(1)
  • DO(n²)、O(n)
查看答案与解析收起答案与解析
答案(62)A (63)D

(62)基本有序 → 插入排序接近最好情况 O(n),空间只用常数个临时变量 O(1),选 A。

(63)基本有序 → 快排最坏,时间 O(n²),递归栈深度 n,空间 O(n),选 D。这组题把“同一个输入,不同算法的命运”考得很透:插入笑、快排哭。

真题 142 2014 下半年 · 题 61、62

快速排序采用的算法设计策略是(61);最好和最坏时间复杂度为(62)。

(61)
  • A分治
  • B动态规划
  • C贪心
  • D回溯
(62)
  • AO(n log n) 和 O(n log n)
  • BO(n log n) 和 O(n²)
  • CO(n²) 和 O(n²)
  • DO(n²) 和 O(n log n)
查看答案与解析收起答案与解析
答案(61)A (62)B

(61)快排把序列划分成两半、分别递归——分治,选 A。

(62)最好情况每次对半分,递归 log n 层、每层 O(n) → O(n log n);最坏情况每次只分出一个元素,递归 n 层、每层 O(n) → O(n²)。选 B。

真题 143 2020 下半年 · 题 62、63

数组 A=(2,8,7,1,3,5,6,4) 以最后一个元素 4 为基准做一趟快速排序划分,结果为(62);一趟划分的计算时间为(63)。

(62)
  • A(1,2,8,7,3,5,6,4)
  • B(1,2,3,4,8,7,5,6)
  • C(2,3,1,4,7,5,6,8)
  • D(2,1,3,4,8,7,5,6)
(63)
  • AO(1)
  • BO(log n)
  • CO(n)
  • DO(n log n)
查看答案与解析收起答案与解析
答案(62)C (63)C

(62)以 4 为基准,从两端向中间扫:左边找比 4 大的(8、7),右边找比 4 小的(1、3、2)……交换后最终 4 归位到下标 3,左边全是 <4 的 2,3,1,右边全是 >4 的 7,5,6,8——(2,3,1,4,7,5,6,8),选 C。

注意左边三个数不要求有序(2,3,1),一趟划分只保证“比基准小的一堆、比基准大的一堆”。

(63)一趟划分要把 n 个元素扫一遍、交换若干次,O(n),选 C。快排总时间 = 划分层数 × 每层 O(n)。

真题 144 2009 上半年 · 题 65

归并排序采用的算法设计方法属于( )。

  • A归纳法
  • B分治法
  • C贪心法
  • D回溯法
查看答案与解析收起答案与解析
答案B

归并 = 把数组分成两半 → 分别递归排序 → 再把两个有序序列合并。典型的“分解—解决—合并”,分治法,选 B。

别和“归纳法”混:归纳法是从小到大递推;归并是分而治之再合并,递归树是自顶向下的。

真题 145 2011 上半年 · 题 65

用插入排序和归并排序对 &lt;3,1,4,1,5,9,6,5&gt; 从小到大排序,分别需要( )次比较。

  • A12,14
  • B10,14
  • C12,16
  • D10,16
查看答案与解析收起答案与解析
答案A

插入排序逐个数逆序:3;1(比 3 → 1 次);4(比 3 → 1 次);1(比 4、3、1 → 3 次);5(比 4 → 1 次);9(比 5 → 1 次);6(比 9、5 → 2 次);5(比 6、5 → 2 次)。合计 11~12 次,取 12。

归并排序两两合并:数组合并的比较次数取决于谁先耗尽——官方答案 14。选 A(12,14)。

这类题的“标准答案”依赖具体的比较计数约定(是否把与哨兵的比较算进去),考场按选项中最接近的官方值选。

真题 146 2012 上半年 · 题 61

递增序列 A 和 B 各长 n、元素互异,合并为长度 2n 的递增序列。最终排列为( )时,归并过程比较次数最多。

  • Aa1…an,b1…bn
  • Bb1…bn,a1…an
  • Ca1,b1,a2,b2,…,an,bn
  • Db1,a1,b2,a2,…,bn,an
查看答案与解析收起答案与解析
答案C

归并比较次数最多的情况是两个序列交替输出——每次比较后只取走一个元素,另一个序列的元素一直“卡”着不走。如果一方全部小于另一方,比较 n 次就能把一方搬完,最省。

C 项正是交错排列(a1,b1,a2,b2,…),每步都要比较,直到最后,比较次数最多。选 C。

真题 147 2013 上半年 · 题 62、63

判断数组中是否存在两数之和为 x:先归并排序,再用双指针从两端向中间找。排序算法采用的策略是(62),整个算法时间复杂度为(63)。

(62)
  • A分治
  • B贪心
  • C动态规划
  • D回溯
(63)
  • AO(n log n)
  • BO(n²)
  • CO(n)
  • DO(log n)
查看答案与解析收起答案与解析
答案(62)A (63)A

(62)归并排序是分治,选 A。

(63)排序 O(n log n),双指针扫描 O(n),总复杂度取大头 O(n log n),选 A。这里是“排序 + 线性扫描”的经典组合,比两两枚举 O(n²) 快一个量级。

真题 148 2017 下半年 · 题 61

递增序列 A(长 m)和 B(长 n)归并为长度 m+n 的递增序列。元素关系为( )时比较次数最少。

  • Aa1<…<am<b1<…<bn
  • Bb1<…<bn<a1<…<am
  • Ca1<b1<a2<b2<…<am<bm<…<bn
  • Db1<a1<b2<a2<…<bm<am<…<bn
查看答案与解析收起答案与解析
答案A

比较次数最少 = 一方全部小于另一方:这样每次比较都取走 A 的元素,比完 m 次 A 就空了,剩下的 B 直接搬过去,不用再比。

所以条件是“A 的最大元素 < B 的最小元素”(或反之),对应选项 A。和第 146 题正好是“最多/最少”的两面。

真题 149 2021 下半年 · 题 62、63

归并排序将数组分成两个大小相同的子数组分别排序,再以 O(n) 合并。该算法采用(62)策略,最好和最坏时间复杂度为(63)。

(62)
  • A分治
  • B动态规划
  • C贪心
  • D回溯
(63)
  • AO(n) 和 O(n log n)
  • BO(n) 和 O(n²)
  • CO(n log n) 和 O(n log n)
  • DO(n log n) 和 O(n²)
查看答案与解析收起答案与解析
答案(62)A (63)C

(62)分成两半分别排序再合并——分治,选 A。

(63)归并排序无论数据怎么排,都要分 log n 层、每层合并 O(n),所以最好最坏都是 O(n log n),选 C。这也是它比快排“稳”的地方:快排最坏 O(n²),归并不看数据脸色。

真题 150 2019 下半年 · 题 62

对 n 个数排序,最坏情况下时间复杂度最低的算法是( )排序。

  • A插入
  • B冒泡
  • C归并
  • D快速
查看答案与解析收起答案与解析
答案C

比较“最坏情况”:插入 O(n²)、冒泡 O(n²)、快速 O(n²),只有归并稳定在 O(n log n)。选 C。

如果题目问“平均”或“最好”,快排和归并都是 O(n log n);问“最坏”就是归并、堆的天下。

真题 151 2021 上半年 · 题 61

初始无序序列,以下排序方法中,( )第一趟结束后一定能将某个元素在最终有序序列中的位置确定下来。①直接插入 ②冒泡 ③简单选择 ④堆 ⑤快速 ⑥归并

  • A①②③⑥
  • B①②③⑤⑥
  • C②③④⑤
  • D③④⑤⑥
查看答案与解析收起答案与解析
答案C

“一趟定一个元素的最终位置”——冒泡每趟把最大(或最小)元素送到最终位置;简单选择每趟选出最小元素放到前面;堆排序每趟取出堆顶放到末尾;快排每趟让基准元素归位。②③④⑤ 都满足,选 C。

①直接插入:第一趟只是把前两个元素排好,它们后面还可能被更小的元素挤动,不能定终位。⑥归并:第一趟只是把相邻两两合并,整体位置未定。

十四、杂题选讲

真题 152 2009 上半年 · 题 58

下面关于图(网)的叙述中,正确的是( )。

  • A连通无向网的最小生成树中,顶点数恰好比边数多 1
  • B若有向图是强连通的,则其边数至少是顶点数的 2 倍
  • C可以采用 AOV 网估算工程的工期
  • D关键路径是 AOE 网中源点至汇点的最短路径
查看答案与解析收起答案与解析
答案A

A 对:生成树就是“用 n−1 条边连通 n 个顶点”,顶点数比边数多 1,任何生成树都成立,与权值无关。

B 错:强连通最少只要 n 条边(一个环),不是 2n。C 错:估算工期用 AOE 网(边表示活动、带权),AOV 网(顶点表示活动)用于拓扑排序、判断先后关系。D 错:关键路径是最长路径,不是最短。

真题 153 2009 上半年 · 题 59

下面关于二叉排序树的叙述,错误的是( )。

  • A中序遍历必定得到有序序列
  • B依无序序列建树,也可能构造出单支树
  • C若建树时进行平衡化处理,则根结点左子树结点数与右子树结点数之差一定不超过 1
  • D若建树时进行平衡化处理,则根结点左子树高度与右子树高度之差一定不超过 1
查看答案与解析收起答案与解析
答案C

C 错:平衡化保证的是高度差不超过 1,不是结点数差不超过 1。左右子树高度相同,结点数可以差很多(一边满、一边稀疏)。

A 对(中序有序);B 对(插入顺序不好会退化成单枝);D 对(AVL 的定义就是高度差 ≤1)。这题专门考“高度”和“结点数”的字眼区别。

真题 154 2009 上半年 · 题 62

广义表 L=((x,y,z),a,(u,t,w)),取出原子项 y 的运算是( )。

  • Ahead(tail(tail(L)))
  • Btail(head(head(L)))
  • Chead(tail(head(L)))
  • Dtail(tail(head(L)))
查看答案与解析收起答案与解析
答案C

一步步取:L = ((x,y,z), a, (u,t,w))。
head(L) = (x,y,z)(第一个元素);
tail((x,y,z)) = (y,z);
head((y,z)) = y。

合起来就是 head(tail(head(L))),选 C。记法:head 取第一个,tail 去掉第一个;要取嵌套里的元素,就从外往里层层剥。

真题 155 2009 下半年 · 题 62

字符串用链表存储,每个结点存多个字符以提高存储密度。在串比较、求子串、串连接、串替换中,( )最不方便。

  • A串比较
  • B求子串
  • C串连接
  • D串替换
查看答案与解析收起答案与解析
答案D

串替换要求“替换后的串长度可以变”,而链式存储按结点分配,长度一变就要大量拆结点、并结点、搬字符,牵一发动全身——最不方便,选 D。

比较、求子串、连接相对好办:比较可以逐结点比,求子串可以定位后截取,连接只需把尾结点指针接上。替换因为“变长”最麻烦。

真题 156 2012 下半年 · 题 61

下图所示为一棵 M 阶 B−树,M 最有可能的值为( )。

  • A1
  • B2
  • C3
  • D4
查看答案与解析收起答案与解析
答案D

M 阶 B−树的关键约束:每个结点最多 M 个孩子、M−1 个关键字;除根外每个结点至少 ⌈M/2⌉ 个孩子。

看图里结点最多有几个孩子(几个分支)——图中结点最多 4 个孩子,所以 M=4,选 D。M 阶的“阶”指的就是“最多孩子数”。

真题 157 2013 上半年 · 题 51

顺序表和单链表存储长度 n 的线性序列,按序号查找元素的时间复杂度分别为( )。(选项为公式图)

  • AO(n)、O(n)
  • BO(1)、O(n)
  • CO(1)、O(1)
  • DO(n)、O(1)
查看答案与解析收起答案与解析
答案B(O(1) 和 O(n))

顺序表:地址 = base + (i−1)×L,一步算出来,O(1)。单链表:从头结点走到第 i 个,走 i 步,O(n)。选 B。

这题是线性表那一节的“收尾题”,把顺序表与链表最本质的差异又考了一遍。

真题 158 2014 上半年 · 题 64、65

Prim 和 Kruscal 都是最小生成树算法。它们采用的策略是(64),且(65)。

(64)
  • A分治
  • B贪心
  • C动态规划
  • D回溯
(65)
  • A若网较稠密,Prim 更好
  • B两算法得到的最小生成树一样
  • CPrim 效率更高
  • DKruscal 效率更高
查看答案与解析收起答案与解析
答案(64)B (65)A

(64)两者都是“每步选当前权值最小的边/顶点”,局部最优推到全局——贪心,选 B。

(65)Prim 的复杂度 O(n²),与边数无关,适合稠密图;Kruscal 的复杂度 O(e log e),适合稀疏图。所以“网较稠密时 Prim 更好”,选 A。B 错:最小生成树可能不唯一(权值相同的边有多个选择时)。

真题 159 2015 上半年 · 题 62、63

优先队列通常采用(62)实现,插入一个元素的时间复杂度为(63)。

(62)
  • A堆
  • B栈
  • C队列
  • D线性表
(63)
  • AO(1)
  • BO(log n)
  • CO(n)
  • DO(n log n)
查看答案与解析收起答案与解析
答案(62)A (63)B

(62)优先队列要“每次取最大/最小”,堆的堆顶正好是极值,插入删除 O(log n)——用堆实现,选 A。

(63)插入堆是“放到末尾再向上调整”,调整层数最多是树高 log n,所以 O(log n),选 B。取堆顶是 O(1),删除堆顶也是 O(log n)。

真题 160 2015 上半年 · 题 64、65

求 n 个数中第 i 小的数,用快排的划分思想,最佳基准元素的选择是(64),此时最坏时间复杂度为(65)。

(64)
  • A第一个
  • B最后一个
  • C中位数
  • D随机一个
(65)
  • AO(n)
  • BO(n log n)
  • CO(n²)
  • DO(log n)
查看答案与解析收起答案与解析
答案(64)C (65)A

(64)选中位数做基准,每次划分最均衡,能把问题规模稳定减半,选 C。

(65)每次只递归处理“包含第 i 小元素的那一半”,总工作量 n + n/2 + n/4 + … ≈ 2n,所以最坏也是 O(n),选 A。这就是“快速选择”算法(BFPRT 思想)。

注意:如果基准选得差(第一个/最后一个),最坏会退化成 O(n²)——所以题目问“最佳选择”时选中位数。

十五、考前速记

  1. 复杂度:保留最高阶、去系数;阶链 1<logn<√n<n<nlogn<n²<n³<2ⁿ<n!。
  2. 主定理:算 n^(log_b a),和 f(n) 比大小,三种情况取大者(同阶乘 log n)。
  3. 顺序表随机访问 O(1)、插删 O(n);链表访问 O(n)、已知位置插删 O(1)。
  4. 单链表删结点难点在找前驱;双向链表才 O(1)。
  5. 栈:后进先出;出栈序列用“模拟 + 数最大深度”。
  6. 栈的应用:递归、表达式求值、括号匹配。
  7. 循环队列:len=(rear−front+M)%M;牺牲一个单元区分空满。
  8. 双端队列同端进出 → 每端退化成栈,序列是两个栈的交错。
  9. 串:空格算字符,空串长度为 0;子串必须连续。
  10. KMP:next[1]=0,其余看“前面子串的最长相等前后缀 +1”。
  11. 二维数组按行:(i−1)N+(j−1);按列:(j−1)M+(i−1)。
  12. 下三角:i(i+1)/2+j;三对角:2i+j(0 基)。
  13. 树:n0 = n2 + 1;结点数 = 边数 + 1 = 度数之和 + 1。
  14. 二叉树:第 i 层最多 2^(i−1);高 h 最多 2^h−1;n 结点高度 ∈ [⌈log₂(n+1)⌉, n]。
  15. 完全二叉树:顺序存储不浪费;高度与结点数一一对应。
  16. 二叉树形态数:n=3→5,n=4→14(卡特兰数)。
  17. 遍历:先序根左右、中序左根右、后序左右根;先序+中序或后序+中序才能唯一建树。
  18. 二叉链表空指针 k+1;三叉链表 k+2。
  19. BST:中序有序;有序插入退化单枝;查找最坏 O(n)。
  20. 哈夫曼:n 个叶子共 2n−1 个结点;无度 1 结点;权小离根远。
  21. 图:无向度数和 2e;完全图 n(n−1)/2;连通最少 n−1。
  22. 邻接矩阵:无向 2e 且对称,有向 e;DFS/BFS 矩阵 O(n²)、邻接表 O(n+e)。
  23. BFS 用队列、DFS 用栈;有回路要访问标记。
  24. 拓扑序列:入度 0 先出;u 在 v 前 ⇒ 不存在 v→u 的弧。
  25. 二分查找:顺序存储 + 有序;最多 ⌊log₂n⌋+1 次;mid 向下取整。
  26. 哈希:装填因子越大冲突越多;p 取不大于 n 的最大质数;线性探测往后找空位。
  27. 堆:父子满足大小关系;建堆 O(n),插入/删除 O(log n)。
  28. 排序稳定性:插入、冒泡、归并、基数稳定;选择、希尔、快排、堆不稳定。
  29. 基本有序 → 插入;范围小 → 计数/基数;要求最坏 O(n log n) → 归并/堆。
  30. 一趟定终位:冒泡、选择、堆、快排。

十六、答案速查表

年份题号答案年份题号答案
2009 下63A2011 下64A
2012 上65C2020 下65D
2012 上62C2010 上64B
2010 下62A2011 上64A
2011 下65A2014 上62、63C、C
2015 下62、63D、C2009 下60D
2010 上65C2011 下58A
2013 下57A2014 上57A
2014 下57A2016 下58、59A、D
2020 下58A2010 上60A
2013 上52B2014 下58D
2016 上57A2017 上58A
2018 下57A2020 下22C
2021 下57B2010 下57D
2013 上53D2013 下58B
2014 上60D2015 上57D
2018 上57A2019 上59A
2021 下58B2009 上60D
2009 下61D2012 上57C
2015 上58B2015 下57B
2021 上57C2017 上57C
2017 下57D2012 下57B
2011 下57B2012 上58A
2014 下60B2011 下21C
2012 上21B2016 下22C
2010 上58A2011 上57A
2015 下58A2018 上58C
2019 上57D2019 下57B
2021 上59B2010 下61B
2019 下59C2011 下60B
2012 上59D2013 上64D
2016 上59D2016 下60C
2019 上58C2021 下59D
2009 上61A2014 上58、59D、C
2017 下59C2018 上59D
2009 下57、58C、B2012 下58A
2015 下59D2017 上59B
2018 下58B2019 下58C
2010 上63C2014 下59C
2016 上58C2016 下61D
2018 下59B2010 上59B
2010 下58C2011 下61C
2012 下64、65B、B2013 下60D
2014 下64、65B、A2016 下62、63A、C
2017 下58A2019 下64、65A、B
2020 下57D2021 下64、65A、A
2011 上59A2015 上59C
2021 上58B2011 下59D
2020 下64B2011 上60C
2012 上60C2015 下61A
2019 下60、61A、A2009 下59D
2016 上61C2017 下60A
2018 上61A2018 下60、61B、B
2010 下59A2012 下60C
2013 下59C2016 下57A
2021 下61B2009 上57C
2010 上57D2010 下60D
2011 上58B2012 下59A
2014 上61B2015 上60B
2015 下60B2016 上60B
2017 上61B2019 上61C
2020 下59C2010 上62B
2011 上61D2013 上65B
2013 下61A2018 上60B
2019 上60见表2021 上60D
2017 上60D2021 上62C
2021 下60C2010 上61C
2012 下62、63A、B2015 下64、65A、D
2017 下64、65A、A2014 下63C
2015 上61A2009 下64、65B、A
2013 下62、63A、D2014 下61、62A、B
2020 下62、63C、C2009 上65B
2011 上65A2012 上61C
2013 上62、63A、A2017 下61A
2021 下62、63A、C2019 下62C
2021 上61C2009 上58A
2009 上59C2009 上62C
2009 下62D2012 下61D
2013 上51B2014 上64、65B、A
2015 上62、63A、B2015 上64、65C、A

写在最后

数据结构这一章,159 道题背后其实只有五个动作:算规模、算位置、算顺序、算数量、比优劣。

  • 算规模:复杂度看循环和递归,主定理套三句话。
  • 算位置:数组、矩阵、顺序存储,全是“前面有多少个元素”的加法。
  • 算顺序:栈、队列、遍历、拓扑,模拟一遍最稳。
  • 算数量:树、图、哈夫曼,公式代进去。
  • 比优劣:顺序 vs 链式、矩阵 vs 邻接表、各种排序的时空稳定性。

把上面的速记过三遍,再把每道题的推导遮住自己写一遍——这一章的分,基本就稳了。

祝备考顺利。