当前课程知识点:数据结构(下) > 第七章 二叉搜索树 > (b3)BST:删除 > 07B3-3 删除:双分支
在这里我们需要再次使用
计算机科学中的一个法宝
也就是化繁为简
具体来说 我们要将比较棘手的
第二种情况
有效地转化为第一种情况
以这样一棵BST为例
假设我们需要从其中删除节点36
可以看到 这个节点
的确是属于比较棘手的情况
因为它的左右后代都同时存在
此时我们不妨找到它的直接后继
没错 直接后继
你应该还记得我们在实现二叉树的时候
对于BinNode类型
曾经定义并且实现过一个名为succ()的接口
你应该记得它的功能与语义
没错 就是返回当前节点
在中序遍历意义下的直接后继
具体来说
也就是在全树中不小于当前节点的
最小的那个节点
回顾当时的这个succ()算法
在当前节点拥有右后代的情况下
算法将首先进入到
它所对应的右子树
然后在右子树中
沿着左侧分支不断地下行
直到最终不能继续下行
而整个过程最终所抵达的那个节点
就应该是当前节点的直接后继
对于这个例子而言
36的直接后继就是40
那么接下来 我们可以
令当前这个节点
与它的直接后继节点互相兑换
比如对这个例子而言
兑换之后的状态 就是这样
你可能会有点担心
因为此时的这棵树
在这个位置违反了顺序性
它已经不再是一棵BST了
是的 你的担心非常有道理
但是其实大可不必
因为这样一种状态
只是一个瞬态
我们马上就会使它重新变为一棵BST
而且能够将目标节点删除掉
是的 此时我们已经可以着手
对这个目标节点实施删除了
难道不是吗?
稍加观察
你不难发现 此时的局部
已经无形中转化为了
此前的第一种情况
也就是说 待删除的36
至多只有一个孩子
更确切地讲
它至多只有右孩子
为什么它不会有左孩子呢?
因为作为此前那个节点的直接后继
它必然是某条左侧分支的末端
作为这个左侧分支的末端
它自然不可能拥有左孩子了
既然如此
我们就可以直接沿用刚才
对情况一的处理手法
也就是直接令它唯一不空的那个孩子
去顶替它
于是我们就可以得到这样一个结果
此时你不难验证
这棵树已经恢复成为了一棵
不折不扣的BST
需要特别说明的是
在此后我们还需要令
内部的_hot变量
指向刚刚被实际删除的这个节点的父亲
并且从它开始
不断地向上追溯历代的祖先
因为这些祖先的高度有可能
因为刚才那个后代的删除
而发生变化
那么同样地
这样一个化繁为简
并且顺利处理的过程
如何描述并且实现为具体的代码呢?
还是回到刚才尚未完成的removeAt算法
我们来补充对第二种情况的处理方法
按照刚才的分析
我们只需要找出当前节点的直接后继
并且令这两个节点的数据域互换
从而等效地将待删除的节点
转移至一个新的位置
而且这个位置至多只有一个分支
当然这个分支只可能是右孩子
为了将待删除的节点
顶替为它的这个右孩子
我们只需在这个右孩子
以及它此前的祖父之间
正确地完成一次双向连接
-选课之前
--写在选课之前
--宣传片
-考核方式
--考核方式
-OJ系统说明
--关于OJ
--1-注册与登录
--2-界面与选课
--3-提交测试
-关于课程教材与讲义
--课程教材与讲义
-关于讨论区
--关于讨论区
-微信平台
--html
-PA晋级申请
--PA晋级
-(a)概述
--07A-1 纵览
--07A-5 接口
-(a)概述--作业
-(b1)BST:查找
-第七章 二叉搜索树--(b1)BST:查找
-(b2)BST:插入
-(b2)BST:插入--作业
-(b3)BST:删除
-第七章 二叉搜索树--(b3)BST:删除
-(c)平衡与等价
-(c)平衡与等价--作业
-(d1)AVL树:重平衡
-第七章 二叉搜索树--(d1)AVL树:重平衡
-(d2)AVL树:插入
-(d2)AVL树:插入--作业
-(d3)AVL树:删除
-(d3)AVL树:删除--作业
-(d4)AVL树:(3+4)-重构
-(d4)AVL树:(3+4)-重构--作业
-本章测验
--章节测验
-(a1)伸展树:逐层伸展
--习题
-(a2)伸展树:双层伸展
--习题
-(a3)伸展树:算法实现
--习题
-(b1)B-树:动机
--习题
-(b2)B-树:结构
--习题
-(b3)B-树:查找
--习题
-(b4)B-树: 插入
--习题
-(b5)B-树: 删除
--习题
-(xa1)红黑树:动机
--习题
-(xa2)红黑树:结构
--习题
-(xa3)红黑树:插入
--习题
-(xa4)红黑树:删除
-本章测验
--习题
-(b)散列:原理
--09B-3 数组
--09B-4 原理
--09B-5 散列
--09B-6 冲突
--习题
-(c)散列:散列函数
--习题
-(d1)散列:排解冲突(1)
--习题
-(d2)散列:排解冲突(2)
--习题
-(e)桶/计数排序
--习题
-本章测验
--本章测试
-(a1)需求与动机
--习题
-(a2)基本实现
--习题
-(b1)完全二叉堆:结构
--习题
-(b2)完全二叉堆:插入与上滤
--习题
-(b3)完全二叉堆:删除与下滤
--习题
-(b4)完全二叉堆:批量建堆
--习题
-(c)堆排序
--习题
-(xa1)左式堆:结构
--习题
-(xa2)左式堆:合并
--习题
-(xa3)左式堆:插入与删除
-本章测验
--本章测试
-(a)ADT
--习题
-(b1)串匹配
--习题
-(b2)蛮力匹配
--习题
-(c1)KMP算法:从记忆力到预知力
--习题
-(c2)KMP算法:查询表
--习题
-(c3)KMP算法:理解next[]表
--习题
-(c4)KMP算法:构造next[]表
--习题
-(c5)KMP算法:分摊分析
--习题
-(c6)KMP算法:再改进
-(d1)BM_BC算法:以终为始
-(d2)BM_BC算法:坏字符
-(d3)BM_BC算法:构造bc[]
-(d4)BM_BC算法:性能分析
-(e1)BM_GS算法:好后缀
-(e2)BM_GS算法:构造gs表
-(e3)BM_GS算法:综合性能
-(f1)Karp-Rabin算法:串即是数
-(f2)Karp-Rabin算法:散列
-本章测验
--本章测试
-(a1)快速排序:算法A
-- 12a1-5: 实例
--习题
-(a2)快速排序:性能分析
--习题
-(a4)快速排序:变种
-(b1)选取:众数
-(b3)选取:通用算法
--习题
-(c1) 希尔排序:Shell序列
--习题
-(c2)希尔排序:逆序对
-本章测验
--本章测试