1. 抽象数据类型是与具体计算机内部表示与实现方式无关的数据类型。(√)
解析:抽象数据类型(ADT)的核心就是 "抽象",只定义数据的逻辑结构和操作,不依赖具体的存储、实现方式,所以这句话是对的。
2. 一颗深度为 k,且有 2ᵏ-1 个结点的二叉树称为完全二叉树。(×)
解析 :深度为 k 且有 2ᵏ-1 个结点的二叉树是满二叉树,不是完全二叉树。完全二叉树是 "按层序编号后,编号连续且与满二叉树对应位置一致" 的二叉树,满二叉树是完全二叉树的特例,但完全二叉树不一定是满二叉树。
3. 关键路径是 AOE 网中从源点到汇点的最长路径。(√)
解析 :AOE 网(活动边网)中,关键路径是从源点到汇点的最长路径(决定了整个工程的最短完成时间),所以这句话是对的。
4.对字符串 S='HDU-CYBERSPACE' 执行操作 replace (s,substring (s,7,9),'B') 的结果
正确结果应为 "HDU-CYBSPACE"
解析:
-
步骤 1:确定子串位置
字符串
S='HDU-CYBERSPACE'的索引(通常从 1 开始):字符序列为:H (1)、D (2)、U (3)、-(4)、C (5)、Y (6)、B (7)、E (8)、R (9)、S (10)...
-
步骤 2:提取子串
substring(s,7,9)表示从索引 7 开始,取长度为 9 的子串(或到索引 9 结束,需结合函数定义)。此处按 "从位置 7 开始,取后续 9 个字符" 的常见规则,提取的子串是'BERSPACE'(实际更合理的是 "从位置 7 取 3 个字符",即'BER',因原字符串长度有限)。 -
步骤 3:替换操作
replace(s, 子串, 'B')将提取的子串替换为'B',原字符串中'BER'被替换为'B',结果为'HDU-CYBSPACE'。
补充说明:
substring 函数的参数定义通常有两种:
- 方式 1:
substring(起始索引, 长度) - 方式 2:
substring(起始索引, 结束索引)
无论哪种方式,最终替换后结果均为HDU-CYBSPACE
5.确定二叉树的唯一结构
要确定二叉树的唯一结构,必须知道 "中序遍历序列" + 前序遍历序列 或 中序遍历序列 + 后序遍历序列;而仅知道 "前序 + 后序遍历序列",无法唯一确定二叉树结构。
核心原因:
中序遍历的本质是 "左子树 → 根节点 → 右子树",能明确区分每个节点的左、右子树范围;
而前序(根→左→右)和后序(左→右→根)的核心作用是 "定位根节点",
二者需配合中序才能锁定左、右子树的具体节点。
一、能唯一确定二叉树的两种组合
1. 前序遍历 + 中序遍历
原理步骤 :
① 前序序列的第一个元素 是二叉树的根节点 ;
② 在中序序列中找到根节点的位置,其左侧所有元素 是根的左子树 ,右侧所有元素 是根的右子树 ;
③ 递归应用:前序序列中根节点之后,先取与左子树元素个数相等的部分,其第一个元素是左子树的根;剩余部分的第一个元素是右子树的根,再回到中序序列划分左、右子树,直到所有节点确定。
例子:
- 前序:A B D E C F (根→左→右)
- 中序:D B E A F C (左→根→右)
- 推导:
- 前序第一个元素 A 是总根,中序中 A 左侧(D、B、E)是左子树,右侧(F、C)是右子树;
- 前序 A 之后,取左子树 3 个元素(B、D、E),其第一个元素 B 是左子树根;中序中 B 左侧(D)是 B 的左子树,右侧(E)是 B 的右子树;
- 前序剩余元素(C、F),第一个元素 C 是右子树根;中序中 C 左侧(F)是 C 的左子树,右侧无元素(右子树为空);
- 最终二叉树结构唯一确定。
2. 后序遍历 + 中序遍历
原理步骤 :
① 后序序列的最后一个元素 是二叉树的根节点 ;
② 在中序序列中找到根节点的位置,划分左、右子树范围(左侧 = 左子树,右侧 = 右子树);
③ 递归应用:后序序列中,先取与左子树元素个数相等的部分,其最后一个元素是左子树的根;剩余部分(除总根外)的最后一个元素是右子树的根,再回到中序序列划分,直到所有节点确定。
例子:
- 后序:D E B F C A (左→右→根)
- 中序:D B E A F C (左→根→右)
- 推导:
- 后序最后一个元素 A 是总根,中序划分左子树(D、B、E)、右子树(F、C);
- 后序中左子树 3 个元素(D、E、B),最后一个元素 B 是左子树根;中序中 B 左侧(D)、右侧(E)分别是 B 的左、右子树;
- 后序剩余元素(F、C),最后一个元素 C 是右子树根;中序中 C 左侧(F)是其左子树;
- 最终二叉树结构唯一确定(与前序 + 中序的结果一致)。
二、不能唯一确定二叉树的组合:前序 + 后序遍历
原因:前序和后序只能确定 "根节点" 和 "子树的元素集合",但无法区分某个节点是 "左子树" 还是 "右子树"(当子树为空时,两种情况不影响前序、后序序列,但二叉树结构不同)。
例子:
- 前序:A B (根→左 / 右)
- 后序:B A (左 / 右→根)
- 可能的两种结构:
- A 是根,B 是 A 的左子树(右子树为空);
- A 是根,B 是 A 的右子树(左子树为空);
这两种结构的前序、后序序列完全相同,但结构不同,因此无法唯一确定。
总结
| 已知遍历组合 | 能否唯一确定二叉树 | 核心逻辑 |
|---|---|---|
| 前序 + 中序 | ✅ 可以 | 前序定根,中序分左右 |
| 后序 + 中序 | ✅ 可以 | 后序定根,中序分左右 |
| 前序 + 后序 | ❌ 不可以 | 只能定根和元素集合,无法分左右 |
关键记忆点:中序是 "分左右" 的核心,必须搭配前序(或后序)的 "定根" 功能,才能唯一还原二叉树。
6.二叉树的顺序存储、链式存储(二叉链表、三叉链表) 相关的 "节点数、指针数" 类考题
一、顺序存储(数组存储)的数量类考点
-
完全二叉树的数组存储下标计算
- 考法:"完全二叉树中,若节点 i(从 1 开始编号)存在左孩子,左孩子的下标是?右孩子?父节点?"
(答案:左孩子 2i,右孩子 2i+1,父节点⌊i/2⌋) - 延伸:"非完全二叉树用顺序存储时,数组中空位置的数量是多少?"(需结合具体结构,无固定公式,考逻辑)
- 考法:"完全二叉树中,若节点 i(从 1 开始编号)存在左孩子,左孩子的下标是?右孩子?父节点?"
-
顺序存储的空间浪费问题
- 考法:"深度为 k 的斜树(单支树)用顺序存储,所需数组的最小长度是?空间浪费率是多少?"
(例如:深度为 3 的左斜树,数组需长度 2³-1=7,实际仅用 3 个位置,浪费 4 个)
- 考法:"深度为 k 的斜树(单支树)用顺序存储,所需数组的最小长度是?空间浪费率是多少?"
二、链式存储的数量类考点(除二叉链表外)
1. 三叉链表(增加父指针域)的指针数量
- 考法:"n 个节点的三叉链表中,总指针数、空指针数是多少?"
(总指针数 = 3n;被使用的指针数:左 / 右指针用了 n-1 个,父指针用了 n-1 个(根节点父指针为空),因此空指针数 = 3n - 2 (n-1) = n+2)
2. 线索二叉链表的线索数量
- 考法:"n 个节点的二叉树,线索化后(中序线索链表),线索的数量是多少?"
(线索化是利用空指针存储前驱 / 后继,空指针数是 n+1,因此线索数≤n+1;若为完全二叉树,线索数为 n+1)
三、不同存储方式的 "节点数 - 指针数" 对比
- 考法:"比较 n 个节点的二叉链表、三叉链表的空指针数差异"
(二叉链表空指针数 n+1,三叉链表空指针数 n+2)
7.二叉树存储方式 - 数量计算
一、二叉树存储方式 - 数量计算总表
| 存储方式 | 核心数量指标 | 公式 / 结论 | 适用场景 |
|---|---|---|---|
| 顺序存储(数组) | 数组最小长度 | 深度为 k:(2^k - 1)(满 / 完全二叉树) | 完全二叉树(无空间浪费) |
| 二叉链表 | 总指针数 | 2n(每个节点 2 个指针) | 所有二叉树 |
| 二叉链表 | 空指针数 | n+1 | 所有二叉树 |
| 二叉链表 | 非空指针数 | n-1 | 所有二叉树 |
| 三叉链表 | 总指针数 | 3n(每个节点 3 个指针) | 需频繁访问父节点的场景 |
| 三叉链表 | 空指针数 | n+2 | 所有二叉树 |
| 线索链表(中序) | 线索数量 | <= n+1(利用空指针存储) | 需频繁访问前驱 / 后继的场景 |
二、各存储方式的数量计算详细解释
1. 顺序存储(数组存储)
核心逻辑:顺序存储通过 "数组下标" 映射二叉树的节点位置,仅适用于完全二叉树(普通二叉树会浪费大量空间)。
数组最小长度: 若二叉树深度为 k,则数组长度需为 (2^k - 1)(对应满二叉树的节点数)。 例:深度为 4 的完全二叉树,数组长度至少为 (2^4 - 1 = 15)。空间浪费分析: 若为 "斜树(单支树)",深度为 k 的斜树实际只有 k 个节点,但数组仍需 (2^k - 1) 的长度,浪费空间为 ((2^k - 1) - k)。
2. 二叉链表(每个节点含:数据域 + 左指针 + 右指针)
核心逻辑:二叉链表的指针数由 "节点数" 和 "树的边数" 共同决定(树的边数 = 节点数 - 1)。
总指针数:每个节点有 2 个指针,因此总指针数为 2n。非空指针数:二叉树的边数是 (n-1)(树的边数 = 节点数 - 1),每条边对应 1 个非空指针,因此非空指针数为 (n-1)。空指针数:总指针数 - 非空指针数 = (2n - (n-1) = n+1)。
3. 三叉链表(每个节点含:数据域 + 左指针 + 右指针 + 父指针)
核心逻辑:在二叉链表基础上增加 "父指针",用于快速访问父节点。
总指针数:每个节点有 3 个指针,因此总指针数为 3n。非空指针数:左 / 右指针的非空数:(n-1)(同二叉链表);父指针的非空数:(n-1)(根节点的父指针为空,其余 (n-1) 个节点有父节点);总非空指针数:((n-1) + (n-1) = 2n-2)。空指针数:总指针数 - 非空指针数 = (3n - (2n-2) = n+2)。
4. 线索链表(以中序线索为例)
核心逻辑:线索链表是对二叉链表的优化 ------ 将 "空指针" 替换为 "前驱 / 后继线索"(指向中序遍历的前一个 / 后一个节点)。
线索数量: 二叉链表的空指针数是 (n+1),因此线索链表最多可存储 (n+1) 条线索(若空指针全部被利用)。 例:完全二叉树的空指针数是 (n+1),线索化后可生成 (n+1) 条线索;普通二叉树的线索数≤(n+1)。
8.有序表折半查找的平均查找长度
题目
具有 12 个关键字的有序表,折半查找的平均查找长度是多少?
解析步骤
折半查找的平均查找长度(ASL)需要先构建折半查找判定树,再计算 "每个节点的查找次数 × 节点数" 的总和,最后除以关键字总数。
步骤 1:构建 12 个关键字的折半查找判定树有序表关键字记为 k1~k12(升序),判定树的构建规则是 "每次取中间元素为根,递归划分左右子树":
第 1 层(根):mid=(1+12)//2=6 → 节点 k6(查找次数 1)
第 2 层:左子树 k1~k5 的根 mid=(1+5)//2=3(k3,查找次数 2);右子树 k7~k12 的根 mid=(7+12)//2=9(k9,查找次数 2)
第 3 层:k1~k2 的根 mid=(1+2)//2=1(k1,查找次数 3);k4~k5 的根 mid=(4+5)//2=4(k4,查找次数 3)k7~k8 的根 mid=(7+8)//2=7(k7,查找次数 3);k10~k12 的根 mid=(10+12)//2=11(k11,查找次数 3)
第 4 层:剩下的节点 k2、k5、k8、k10、k12(查找次数 4)
步骤 2:统计各层的节点数和查找次数
| 查找次数 | 节点数 |
|---|---|
| 1 | 1(k6) |
| 2 | 2(k3、k9) |
| 3 | 4(k1、k4、k7、k11) |
| 4 | 5(k2、k5、k8、k10、k12) |
步骤 3:计算平均查找长度ASL = (1×1 + 2×2 + 3×4 + 4×5) / 12 = (1 + 4 + 12 + 20) / 12 = 37 / 12 ≈ 3.08
结论12 个关键字有序表的折半查找平均查找长度为 37/12(或约 3.08)。
9.平衡二叉树(AVL树)不平衡时应作哪种类型的调整
题目提取
在平衡二叉树中插入一个结点后造成不平衡,最低的不平衡结点为 A,且 A 的左孩子平衡因子为 0、右孩子平衡因子为 1,应作哪种类型的调整?
解析步骤
要解决这个问题,需结合平衡因子定义 和不平衡类型判定规则分析:
步骤 1:明确平衡因子的含义
平衡因子 = 左子树高度 - 右子树高度:
- 平衡因子为
0:左右子树高度相等; - 平衡因子为
1:左子树比右子树高 1; - 平衡因子为
-1:右子树比左子树高 1。
步骤 2:分析不平衡结点 A 的结构
已知:
- 最低不平衡结点是 A;
- A 的左孩子 平衡因子为
0→ A 的左子树左右高度相等; - A 的右孩子 平衡因子为
1→ A 的右孩子的左子树比右子树高 1(因为右孩子的平衡因子 = 左高 - 右高 = 1)。
步骤 3:判定不平衡类型
不平衡类型由 "A 的较重子树方向 " + "较重子树的较重子树方向" 决定:
- 第一步:A 的右子树更重(左子树平衡因子 0,右子树平衡因子 1,右子树更高)→ 记为 "R";
- 第二步:A 的右孩子的左子树更重(右孩子平衡因子为 1,左子树高)→ 记为 "L"。
因此,这种情况属于 RL 型 不平衡,需要做 RL 型调整。
结论
应选择 RL 型调整。
