(e5)重构

官官方信息技术老师·15 页·深入(追求细节与边界)·0 次浏览·38 天前
二叉树遍历递归算法

由遍历序列重构二叉树

看完你能亲手推导前序+中序如何唯一确定一棵二叉树,并说清什么组合做不到

按 空格/→ 演示下一步

问一句
1 / 15 页

全部页面点击任意一页,跳回舞台从这页播放

二叉树遍历递归算法

由遍历序列重构二叉树

看完你能亲手推导前序+中序如何唯一确定一棵二叉树,并说清什么组合做不到

1第 1 页 · 由遍历序列重构二叉树

遍历序列回顾

上一页我们看到:光有一棵树的先序遍历,无法唯一还原树——就像只知道一家人的名单,画不出家谱。原因藏在这三个序列的定义里:根出现的位置不同,留下的线索也就不同。

先序:根最前
根在序列开头,其余是左右子树拼接
中序:根居中
根把序列切成左子树段和右子树段
后序:根最后
根收尾,前面的部分是左右子树
关键互补
任一种给根的位置,中序负责划分子树边界
切蛋糕对应 →中序遍历

刀落下的位置把蛋糕分成左右两块,对应根切分左右子树

2第 2 页 · 遍历序列回顾

一种序列为何不够

左右两棵树形状不同,但先序访问都是 A→B→C:同一序列对应多种结构。

图解渲染中…
a1:先序=根左右:A 先访问,再进左子树b2:树2 中 A 没有左子树,B 挂在右侧c1:树1 中 C 是 B 的右孩子;树2 中 C 是 B 的左孩子
3第 3 页 · 一种序列为何不够

核心原理:先序定根

上一页我们看到,单独一种遍历序列无法唯一确定一棵二叉树。但如果同时拿到两种序列呢?先序负责指认根,中序负责切分左右——两个角色分工配合,整棵树就能逐层还原。

先序首元素定根
当前序列段的第一个元素,就是这棵(子)树的根
中序找根切两半
在中序中定位根,左侧全部是左子树,右侧全部是右子树
左右各自递归
左右子树仍是同样问题,用对应序列片段重复以上两步
排队伍找班长对应 →先序+中序重构

先序负责每段队伍的排头(根),中序里排头左边的都归左队

n 个节点的子树:先序段 [s1..sn], 根=s1; 中序中根位置 k⇒左子树 k−1 个,右子树 n−k 个n\text{ 个节点的子树:先序段 }[s_1..s_n],\ \text{根}=s_1;\ \text{中序中根位置 }k\Rightarrow\text{左子树 }k-1\text{ 个,右子树 }n-k\text{ 个}
4第 4 页 · 核心原理:先序定根

重构五步流程

前序+中序两列序列,五步把每个节点钉回原位。

1
找根
取前序序列第一个元素,它必是当前子树的根
2
切中序
在中序序列里定位根,左边为左子树,右边为右子树
3
切前序
按左子树节点数,把前序剩余段切成左段和右段
4
递归
对左右两段各自回到第一步,规模减半继续拆
5
归位
段空或只剩一个节点时直接落子,全树重构完成
5第 5 页 · 重构五步流程

完整实例演练

用一个具体序列对完整走一遍递归切分过程

完整实例演练
用一个具体序列对完整走一遍递归切分过程
6第 6 页 · 完整实例演练

递归代码实现

python

从先序+中序重构二叉树的最小可运行实现,看清切分下标怎么算。

代码高亮加载中…

mid 同时是三把尺子:中序切左右、先序定根后切左右,两侧切片长度必须同为 mid,边界差一即错。

7第 7 页 · 递归代码实现

后序+中序:异同辨析

很多人背完先序版就混了:后序版到底哪里不同?其实只有一处。

先序 + 中序
  • 根 = 先序序列第一个元素
  • 在中序中找根,划分左右子树
  • 递归重建,流程完全相同
后序 + 中序
  • 根 = 后序序列最后一个元素
  • 在中序中找根,划分左右子树
  • 递归重建,流程完全相同
唯一差异在取根位置:先序取头、后序取尾;中序切分与递归逻辑两版一致。
8第 8 页 · 后序+中序:异同辨析

自测:序列重构

点击作答

已知先序+中序序列可唯一重构二叉树。若把中序换成后序(先序+后序),结论如何?

9第 9 页 · 自测:序列重构

先序+后序为何失效

中序能救场,是因为它把左右子树分了家。那先序+后序呢?两者都把根放在两端,中间全是孩子——听起来信息不少,可遇上只有一个孩子的节点,麻烦就来了。

根信息重复
先序根在前、后序根在后,两者对「根在哪」的说法完全重复
缺左右分界
没有中序,就无法知道先序里哪些元素属于左子树、哪些属于右子树
单孩子歧义
只有一个孩子的节点,无法判断该孩子在左边还是右边,两种树先序后序全同
知道队伍人数对应 →子树划分

知道每段有几个人,不等于知道谁站左边谁站右边

10第 10 页 · 先序+后序为何失效

反例演示

同一对先序后序序列,能还原出两棵结构不同的树——这就是唯一性失效现场。

图解渲染中…
a1:两树中 B 的位置不同:左孩子 vs 右孩子s1:先序 AB、后序 BA:A 是根,B 是唯一孩子c1:「无」表示该侧没有子树
11第 11 页 · 反例演示

真二叉树:可重构条件

前面我们看到,先序+后序对普通二叉树会失效——某个节点只有一个孩子时,分不清它在左还是右。那什么时候这个组合才可靠?答案藏在一个特殊条件里:每个节点要么是叶子,要么恰有两个孩子。

真二叉树
每个节点度数为 0 或 2,不存在单孩子节点
失效根源消失
单孩子时左右归属不定;真二叉树排除了这种情况
先序+后序唯一
每步分根下的左右段时不再有歧义
反例启示
前页的歧义树必有单孩子,正是条件被破坏的体现
两人对口令对应 →真二叉树重构

只有双方各答一句(左右都有回应),位置才唯一确定

12第 12 页 · 真二叉树:可重构条件

真二叉树重构流程

真二叉树下,先序+后序终于够用:首末匹配定根,余下元素对半分出左右子树。

1
先序首、后序末定根
先序第一个与后序最后一个必是整棵树的根,先取根
2
首末重合验证
两序列除根外恰好对半拆分,是可重构的前提
3
先序次元素定左根
先序第二个元素是左子树根,记其值用于下一步定位
4
后序中定位边界
在后序中找左子树根的位置,其左侧含自身即整个左子树
5
切分两对子序列
先序、后序各切出左右两段,递归处理右子树同理
6
递归到叶
子问题规模缩小直至单结点,拼回即得唯一真二叉树
13第 13 页 · 真二叉树重构流程

要点收束

  • ✓单独任一序列都丢信息,无法唯一定树
  • ✓先序定根、中序分左右,配对即递归
  • ✓后序+中序同理,只是根在序列末尾
  • ✓先序+后序缺「独子归左还是右」的判断
  • ✓真二叉树无独子,先序+后序即可重构
延伸主题:层序+中序重构怎么做重构的时空复杂度分析序列重构在序列化中的应用
14第 14 页 · 要点收束

课后思考

先合上讲义自己想十分钟,再对照参考答案。

1为什么「先序定根、中序分左右」这一对分工缺一不可?少了中序,根把序列切不开的具体障碍在哪?

参考答案先序只告诉你根是谁,但根两侧各有多少节点、哪些属于左子树,只有中序能提供。没有这个切分点,递归第一步就卡住,子问题规模无法确定。

2如果把方法推广到三叉树:先序+中序还能唯一重构吗?需要什么额外信息?

参考答案中序里根的左右各只剩一段,无法分出三个子树的边界。需要每个节点记录孩子数量,或改用「孩子数可区分的遍历序」才能切开。

3真二叉树让先序+后序可重构,这一条件还能再放宽吗?还是已经到达边界?

参考答案不能随意放宽:只要存在度为1的节点,就无法判断它的唯一孩子挂在哪侧。真二叉树恰好消除了所有这类歧义,这已是该信息量下的边界。

15第 15 页 · 课后思考