已知森林
目标
- 独立辨析森林与二叉树的转换中的核心概念、结构性质与算法关系;
- 对选择题写出排除干扰项的依据,而不只记忆答案字母;
- 对本组已有的综合题完成推导、算法设计或复杂度分析。
前置知识
建议先阅读4.5 树、森林与二叉树和第 5 章概览,再开始本组练习。
环境、输入与预期输出
- 环境:任意现代浏览器;综合题建议准备纸笔或本地编辑器。
- 输入:16 道四选一选择题,1 道综合题。
- 预期输出:一份独立作答记录,以及每道错题或综合题的完整推理过程。
作答方法
- 选择题先独立判断并记录依据,再点击“提交答案”;
- 提交后核对正确答案和解析,做错的题使用“重新作答”;
- 综合题先完成推导、伪代码或代码,再展开参考答案逐项核对;
- 对易混概念主动构造反例,说明条件变化后结论是否仍成立。
选择题
某森林 F 对应的二叉树为 T , 若 T 的先序遍历序列是 a, b, d, c, e, g, f , 中序遍历序列是 b, d, a, e, g, c, f , 则 F 中树的棵数是( )。
将森林
将下列二叉树逆转换为森林(视作孩子兄弟法的结果):
A(B(D, E), C(_, F))
转换后森林共有( )棵树。
一片森林
森林
关于森林
① 转换前后结点总数相等。 ②
的先根遍历 = 的前序遍历。 ③ 的后根遍历 = 的后序遍历。 ④ 若 含 棵树( ),则 的根总是没有右子树。
森林
已知森林
那么关于森林
设
设森林
设森林
利用二叉链表存储森林时,根结点的右指针是( )。
在森林的二叉树表示中,结点
森林
设森林
答案总览(建议完成全部题目后查看)
- 第 1 题:C
- 第 2 题:C
- 第 3 题:A
- 第 4 题:C
- 第 5 题:C
- 第 6 题:C
- 第 7 题:B
- 第 8 题:A
- 第 9 题:D
- 第 10 题:D
- 第 11 题:C
- 第 12 题:D
- 第 13 题:D
- 第 14 题:B
- 第 15 题:B
- 第 16 题:A
综合题
综合题 1
难度:★★★ · 分值:12 分
考点:树与森林、森林与二叉树的转换、森林、二叉树、孩子兄弟法、先根遍历、转换演算
设森林
树 1(根 A):
- A:B, C, D
- B:E, F
- C:(叶)
- D:G
- E, F, G:(叶)
树 2(根 H):
- H:I, J
- I:(叶)
- J:K
- K:(叶)
树 3(根 L):
- L:M
- M:(叶)
请完成下列任务:
(1) 用 孩子兄弟链表(亦称"左孩子-右兄弟"表示法)把森林
(2) 写出原森林
(3) 写出转换后二叉树
(4) 证明 (2) 与 (3) 得到的两序列完全相同,并解释这一性质成立的根本原因。
已知条件:
- 森林到二叉树的转换规则(孩子兄弟法):
- 二叉树中结点
的左指针 = 原森林中 的第一个孩子(若无孩子则为空); - 二叉树中结点
的右指针 = 原森林中 的下一个兄弟(若无下一个兄弟则为空); - 森林中多棵树的根互为兄弟——即第
棵树的根,其右指针指向第 棵树的根(最后一棵的根右指针为空)。
- 二叉树中结点
的根 = 中第一棵树的根。
参考答案与详细解析
详细解析
思路分析
转换规则的两层语义
孩子兄弟链表表面看是一棵二叉树,但每个指针在原森林里有明确的层级语义:
- 左指针走一步 = 在原森林中下移一层(从父到子);
- 右指针走一步 = 在原森林中保持在同一层(同父下的下一个兄弟,或下一棵树的根与当前根视为同层兄弟)。
这种"二叉树形 + 森林语义"的双重视角是本题所有演算的基础。
先根遍历与先序遍历相同的核心洞察
森林的"先根遍历"次序:访问当前根 → 对每棵子树依次先根遍历 → 当前根的所有后代访问完后转到下一棵兄弟树。
二叉树
把两条规则平铺:
- 二叉树先序 "访问当前根" = 森林先根 "访问当前根"(同一物理结点);
- 二叉树先序 "递归左子树" = 沿左指针下移一层 = 森林先根 "递归当前结点的第一棵子树"(首孩子开始);
- 二叉树先序的左子树内部继续按"根 → 左 → 右"展开 = 在原森林视角下依次访问"首孩子的子树 → 第二个孩子(首孩子的右兄弟)的子树 → 第三个孩子的子树 → ..." = 恰好是森林对当前结点子树的"依次先根遍历";
- 二叉树先序 "右子树" = 沿右指针走到下一个兄弟(或下一棵树的根)= 森林先根 "当前结点访问完所有后代后转到下一个兄弟"。
四条规则一一对应,所以两序列逐位完全相等——这是孩子兄弟法的不变量之一,与"森林后根遍历 = 二叉树中序遍历"对偶。
演算过程
Step 1:逐结点列出"左指针 / 右指针"对照表
按转换规则填表("空"表示空指针):
| 结点 | 第一个孩子(左指针) | 下一个兄弟(右指针) | 备注 |
|---|---|---|---|
| A | B | H | A 是森林第 1 棵树根,下一棵树根 H 即兄弟 |
| B | E | C | B 是 A 的首孩子,A 的孩子序 B→C→D,故 B 的下一兄弟为 C |
| C | 空 | D | C 无孩子;C 的下一兄弟为 D |
| D | G | 空 | D 有唯一孩子 G;D 是 A 的最后一个孩子,无下一兄弟 |
| E | 空 | F | E 无孩子;E 的下一兄弟为 F |
| F | 空 | 空 | F 无孩子且是 B 的最后一个孩子 |
| G | 空 | 空 | G 无孩子且 D 仅有 G 一个孩子 |
| H | I | L | H 是森林第 2 棵树根,下一棵树根 L 是兄弟 |
| I | 空 | J | I 无孩子;I 的下一兄弟为 J |
| J | K | 空 | J 有唯一孩子 K;J 是 H 的最后一个孩子 |
| K | 空 | 空 | K 是叶 |
| L | M | 空 | L 是森林第 3 棵树根,无下一棵树 |
| M | 空 | 空 | M 是叶 |
Step 2:画出转换后的二叉树 (任务 1)
按 Step 1 的对照表,二叉树的紧凑括号表示为:
A 的左 = B、右 = H
B 的左 = E、右 = C
E 的左 = 空、右 = F
F 的左 = 空、右 = 空
C 的左 = 空、右 = D
D 的左 = G、右 = 空
G 的左 = 空、右 = 空
H 的左 = I、右 = L
I 的左 = 空、右 = J
J 的左 = K、右 = 空
K 的左 = 空、右 = 空
L 的左 = M、右 = 空
M 的左 = 空、右 = 空二叉树形态:
A(B(E(_, F), C(_, D(G, _))), H(I(_, J(K, _)), L(M, _)))结构核查:
- 根 A 的右子树(H 子树)对应森林中第 2、第 3 棵树的"串"——A → 右指针 → H → 右指针 → L,与"森林根之间互为兄弟"的约定一致;
- 任意叶结点(C 在原森林是叶但在
中右指针非空指向 D,所以不是 的叶;真正 的叶 = 左右指针都空 = F、G、K、M 共 4 个,少于森林叶子数 7)——这印证了本组选择题中的结论"森林叶子数 = 二叉树中左指针为空的结点数",本题中左指针为空的结点为 C、E、F、G、I、K、M 恰好 7 个 ✓。
Step 3:森林 的先根遍历序列(任务 2)
按"先访问根 → 递归先根遍历每棵子树 → 下一棵兄弟树"逐步展开:
树 1(根 A):
- 访问 A;
- 递归先根遍历 A 的第一棵子树(B 的子树):访问 B → 递归 B 的子树 E 的子树 → 访问 E → 递归 E 的子树(空,跳过)→ 递归 B 的子树 F 的子树 → 访问 F → F 子树空;
- 递归 A 的第二棵子树(C 的子树):访问 C → C 子树空;
- 递归 A 的第三棵子树(D 的子树):访问 D → 递归 D 的子树 G → 访问 G;
树 1 序列:A, B, E, F, C, D, G
树 2(根 H):
- 访问 H;
- 递归 H 的子树 I:访问 I → I 子树空;
- 递归 H 的子树 J:访问 J → 递归 J 的子树 K → 访问 K;
树 2 序列:H, I, J, K
树 3(根 L):
- 访问 L;
- 递归 L 的子树 M:访问 M;
树 3 序列:L, M
森林先根遍历序列(任务 2 答案):
Step 4:二叉树 的先序遍历序列(任务 3)
按"根 → 左 → 右"递归展开:
- 访问 A → 进入 A 的左(B 子树)→ 访问 B → 进入 B 的左(E)→ 访问 E → E 的左空,进入 E 的右(F)→ 访问 F → F 左右空,回溯到 E 的右处理完,回溯到 B 的左处理完;
- 进入 B 的右(C)→ 访问 C → C 的左空,进入 C 的右(D)→ 访问 D → 进入 D 的左(G)→ 访问 G → G 左右空,回溯到 D 的右空,回溯到 C 的右处理完,回溯到 B 的右处理完;
- 回溯到 A 的左处理完,进入 A 的右(H)→ 访问 H → 进入 H 的左(I)→ 访问 I → I 的左空,进入 I 的右(J)→ 访问 J → 进入 J 的左(K)→ 访问 K → K 左右空,回溯到 J 的右空,回溯到 I 的右处理完,回溯到 H 的左处理完;
- 进入 H 的右(L)→ 访问 L → 进入 L 的左(M)→ 访问 M → M 左右空,回溯到 L 的右空,回溯结束。
二叉树先序遍历序列(任务 3 答案):
Step 5:两序列一一对应的证明(任务 4)
逐位对照:
| 位置 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 森林先根 | A | B | E | F | C | D | G | H | I | J | K | L | M |
| 二叉树先序 | A | B | E | F | C | D | G | H | I | J | K | L | M |
逐位完全相等 ✓
根本原因(数学归纳法 + 直观对应):
设结点
- 情况 ①:
在森林中有孩子(即左指针非空)。先根序的下一个 = 的第一个孩子 = 二叉树中 的左孩子。这与二叉树先序"根之后第一个访问的是左孩子"完全一致。 - 情况 ②:
在森林中无孩子但有兄弟(左空、右非空)。先根序的下一个 = 的下一个兄弟(同父或下一棵树根)= 二叉树中 的右孩子。又因为二叉树先序在左子树空时直接进入右子树,所以二叉树先序的下一个也是右孩子 ✓ - 情况 ③:
既无孩子也无兄弟(左右指针都空)。先根序回溯到某个最近的、有未被访问的下一个兄弟的祖先 ,访问 的"下一兄弟"。在二叉树中"沿右指针向上回溯"的语义恰好是同一件事——因为右指针在森林视角下就是"同层下一个未被访问"。
三种情况覆盖所有递归路径,逐步推得两序列一一对应。形式化地:
其中
结论:森林的先根遍历与二叉树的先序遍历是孩子兄弟链表下的对偶性质——这条不变量与"森林后根遍历 = 二叉树中序遍历"配对,构成课程必背的两对等价关系。
易错点
本题不在"想不到孩子兄弟法"——而在 (a) 误把森林根之间画成不相关或"父子关系"、(b) 转换后误以为森林叶 = 二叉树叶、(c) 把"森林先根 = 二叉树先序"的根本原因背成"刚好一样"而无法解释为什么。
盲区 A:「林根有兄弟二叉根无兄弟」的隐式约定
学习者看到"森林有 3 棵树"的本能反应是"给三棵树各转一棵二叉树,再拼起来"。但题目要求整片森林对应一棵二叉树——通过"第
棵树根 → 右指针 → 第 棵树根"把多棵树串成同一棵二叉树的右链。错误推演:若学习者把 A 的右指针设为空("A 没有兄弟"),则二叉树只反映了树 1,丢失了树 2 和树 3。森林先根遍历会得到 13 个结点,但二叉树先序只得到树 1 的 7 个结点 = A, B, E, F, C, D, G——少了 6 个。
正解:森林根之间在二叉树中互为右兄弟链。
的根本身没有"兄弟"(二叉树根无父),但 的根的右子树承担了"森林其余树"的语义。这条规则命名为「林根兄弟链」,在**盲区 B:「森林叶 ↔ 二叉树叶」的漂移(
学习者看到"森林有 7 个叶"立刻数二叉树叶——但二叉树叶(左右指针都空)只有 F、G、K、M 共 4 个,比森林叶少。
错误推演:直接以"二叉树叶 = 森林叶"为约定算结点数会少 3 个,影响后续涉及"叶数"或"内部结点数"的问题。
正解:森林叶 = 二叉树中左指针为空的结点数(不论右指针是否非空)。本题中左空结点为 C、E、F、G、I、K、M 共 7 个,与森林叶一一对应(详见本题解析)。这条对偶映射是孩子兄弟法的核心不变量。
盲区 C:「右指针含义在森林中是兄弟」的误读
学习者记成"右指针 = 父亲"或"右指针 = 树根之间的某种连接"。
错误推演:若误以为 B 的右指针指向 A(父),则二叉树画出来根 A 同时是 B、E、F、C、D、G 的右上方"祖先"——这破坏了二叉树本身的"父子单向"性质,画出来根本不是合法的二叉树。
正解:右指针永远是"原森林中同一层的下一个结点"——同父的下一兄弟、或下一棵树根(当本结点是某棵树的根时)。沿右指针单向走是"横向遍历",沿左指针单向走是"纵向下移"。两种边的语义不可混。这条认知盲区
盲区 D:「单独转换 + 拼接」误以为多棵树要先分别转再合并
学习者写:先把树 1 转成二叉树
、树 2 转成 、树 3 转成 ,再"想办法拼起来"。错误推演:拼接时不知道挂在哪——挂到
的根右?挂到 最右叶?两种拼法都不是孩子兄弟法的规范。容易写出 的根 A 同时挂 在右指针(即 A.right = H, H.right = L)的形式——这其实等价于正解,但通过"绕了一圈再发现"得到,浪费考场时间。正解:从一开始就把森林作为整体处理——给森林根列表
在二叉树中铺成右链 ,再对每棵树内部按"左孩子 = 首孩子、右孩子 = 同父下一兄弟"递归填左右。先整再分 的视角比"分别转换再拼"少出错且 5 行就能写完转换。盲区 E(元层):「先根遍历 = 先序遍历,是巧合还是定理?」
学习者发现两序列相等后觉得"碰巧吧,不一定每次都成立",于是考试时遇到大森林手算两遍验证,浪费时间且容易抄错。
错误推演:学习者在考场上手工写"森林先根 = 二叉树先序"两遍后核对,发现不一致——多半是某次回溯写漏一步——于是耗费 5 分钟纠错。
正解共识(让学习者敢直接套):这是定理,不是巧合。证明详 Step 5 的三种情况分析。学习者只需记住"森林先根 = 二叉树先序 / 森林后根 = 二叉树中序"两对对偶等式(注意森林没有对应"二叉树后序"的自然遍历——森林中根访问完所有子树之前没有"中间访问"的位置),考场上直接互用免去重复劳动。这条认知归口为「孩子兄弟法的两个等式」,与"森林叶数 = 二叉树左空数"同属孩子兄弟法不变量族。
完成清单
复盘
- 哪道题最容易因结构关系、边界口径或算法步骤判断失误?
- 我能否不用背答案,重新画出结构或写出关键操作过程?
- 如果题目改变一个条件,原结论是否仍成立?