(b3)BST:删除

官方信息技术老师·14 页·深入(追求细节与边界)·0 次浏览·2 天前
BST删除操作树重连边界情况

BST:删除

看完你能独立处理三种BST删除情形,吃透每步树重连的原理

按 空格/→ 演示下一步

1 / 14 页

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

BST删除操作树重连边界情况

BST:删除

看完你能独立处理三种BST删除情形,吃透每步树重连的原理

1第 1 页 · BST:删除

删除节点的三种情况

从要删的节点出发,按子节点数量分三条路。

图解渲染中…
d1中序后继,即右子树中的最小节点b2只有一个左孩子或右孩子d2只复制后继的值,不搬整个子树
2第 2 页 · 删除节点的三种情况

删除函数框架

python

把 BST 删除的完整骨架一次性摊开:外层递归负责定位,命中后按三种情况分别处理。

代码高亮加载中…

外层递归负责向下定位,命中后 `else` 块按「左空 / 右空 / 双儿」三路分支,把三种删除情况落到具体行。

3第 3 页 · 删除函数框架

叶子节点的删除

无子节点时直接断开连接

叶子节点的删除
无子节点时直接断开连接
4第 4 页 · 叶子节点的删除

单子节点的删除

左右两棵子树分别是删除前与删除后,中间箭头标出核心操作。

图解渲染中…
a2标"删"字的就是目标节点30a130的父节点50,改指针绕过30a330唯一的子节点20,将接替其位置
5第 5 页 · 单子节点的删除

单分支删除代码

python

三行代码同时搞定「单子节点」与「叶子节点」删除,关键在 NULL 子树的处理。

代码高亮加载中…

两段 if 同时覆盖「单子节点」与「叶子节点」删除:返回值可能是 None,父节点指针自然被改写。

6第 6 页 · 单分支删除代码

后继节点是什么

前面搞定了叶子节点和单子节点两种情况。剩下最棘手的——左右孩子都在——要用到一个关键角色:后继节点。它到底是谁?为什么偏偏是它?

后继的定义
中序遍历中,当前节点的下一个节点
右子树最左下
等价于「进右子树后一路向左到底」
为什么选它
它是比当前节点大的最小值,替换不破坏 BST
什么时候用
左右孩子都存在时,用它替换待删节点
排队时下一个比我高的人对应 →后继节点

去高个子那队,再挑里面最矮的

7第 7 页 · 后继节点是什么

后继节点位置

图示找到后继的路径

后继节点位置
图示找到后继的路径
8第 8 页 · 后继节点位置

后继 vs 前驱

两种替换策略都能正确删除双子节点,学生常纠结「该用哪个」。其实它们完全对称。

后继(右子树最小)
  • 找法:向右一步,再一路向左到底
  • 形态:至多只有右孩子,没有左孩子
  • 删除:从右子树把它真正删掉
前驱(左子树最大)
  • 找法:向左一步,再一路向右到底
  • 形态:至多只有左孩子,没有右孩子
  • 删除:从左子树把它真正删掉
两者完全对称,都正确。多数实现默认用后继——递归时从右子树删除更顺手。选哪个都行,关键是替换后把它从原位置真正删掉。
9第 9 页 · 后继 vs 前驱

双分支删除流程

双子节点删除拆三步:找后继、替换值、递归删后继。

1
找后继
在待删节点的右子树一路向左,找最小节点作替补
2
替换值
把后继值复制到待删节点,位置和子树都不动
3
递归删后继
对后继原位置递归调用删除,它至多只有一个右孩子
10第 10 页 · 双分支删除流程

双分支删除完整代码

python

完整 delete 函数:用 find_min 找后继,复制键值,再递归把后继从右子树删掉。

代码高亮加载中…

第19行确认命中目标;24–26行是双分支核心——找后继、覆盖键、递归删后继。后继没有左子,下次递归自然走单子分支退路,循环不会死。

11第 11 页 · 双分支删除完整代码

删除的复杂度

前面三种删除情况都讲完了。现在问效率:双分支要沿树向下找后继——这条路径有多长?这取决于树的形状。

找后继是主要开销
双分支删除要在右子树一路向左下走找最小值
最好情况 O(1)
删叶子或单子节点直接改指针,一步完成
最坏情况 O(h)
从根沿路径走到叶,h 是树的高度
h 受树形影响
平衡树 h≈log n;斜树 h=n 退化为顺序查找
查字典对应 →BST 删除复杂度

对半翻字典像平衡树 O(log n),逐字翻像斜树 O(n)

Tdelete=O(h),h[logn, n]T_{\text{delete}} = O(h),\quad h \in [\log n,\ n]
12第 12 页 · 删除的复杂度

BST删除要点回顾

  • 双分支本质是「替换值 + 删除后继」,最终都回到单子节点情况
  • 替换值 ≠ 删除节点:必须把后继节点本身从原位置摘除
  • 删除改的是父节点的指针,递归靠返回值把新子树根传回上层
  • 复杂度即树高 h,平衡时 O(log n),链状时退化到 O(n)
  • 后继默认选右子树最左节点,可保证 BST 仍有序
延伸主题:自平衡BST如何避免退化删除的迭代实现与父指针后继 vs 前驱:何时该选哪个
13第 13 页 · BST删除要点回顾

课后思考

先独立思考再看参考答案,看每条要点能想到几个。

1为什么双分支删除要选后继或前驱来填补,而不是随便选一个节点?

参考答案后继一定没有左孩子,前驱一定没有右孩子,填补后仍满足左小右大。随便选会破坏BST有序性。

2如果BST允许重复键,删除时遇到重复值该如何处理?

参考答案需约定重复值放左还是右子树。删除时按约定定位,或在节点维护计数器批量处理。

3AVL树或红黑树的删除比BST复杂在哪?后继替换还直接适用吗?

参考答案AVL/红黑树删除后还需旋转或变色恢复平衡。后继替换仍可复用,但平衡调整使其更复杂。

14第 14 页 · 课后思考