删除二叉搜索树中的节点
LeetCode450. 删除二叉搜索树中的节点
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点;
如果找到了,删除它。
思路
搜索树的节点删除要比节点增加复杂的多,有很多情况需要考虑
- 第一种情况:没找到删除的节点,遍历到空节点直接返回了
- 找到删除的节点
- 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
- 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
- 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
- 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
第五种情况例:
这里再介绍一种通用的删除,普通二叉树的删除方式(没有使用搜索树的特性,遍历整棵树),用交换值的操作来删除目标节点。
代码中目标节点(要删除的节点)被操作了两次:
- 第一次是和目标节点的右子树最左面节点交换。
- 第二次直接被NULL覆盖了。
代码
Go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
// 通用的二叉树的删除方式
func deleteNode(root *TreeNode, key int) *TreeNode {
if root == nil {
return nil
}
if key < root.Val { // key < root 向左搜索
root.Left = deleteNode(root.Left, key)
return root
}
if key > root.Val { // key > root 向右搜索
root.Right = deleteNode(root.Right, key)
return root
}
// 找到目标节点
if root.Right == nil { // 目标节点的右孩子为空
return root.Left // 返回左孩子
}
if root.Left == nil { // 目标节点的左孩子为空
return root.Right // 返回右孩子
}
// 目标节点的左右孩子都非空
minNode := root.Right // 保存目标节点的右子树到minNode中
for minNode.Left != nil { // 找到目标节点的右子树的最左面节点
// 保存目标节点的右子树的最左面节点到minNode中
minNode = minNode.Left
}
root.Val = minNode.Val // 目标节点的值改为其右子树的最左面节点的值
root.Right = deleteNode1(root.Right) // 目标节点的右子树
return root
}
// 删除目标节点的右子树的最左面节点
func deleteNode1(root *TreeNode) *TreeNode {
if root.Left == nil { // 若传入节点的左孩子为空
pRight := root.Right // 保存传入节点的右子树到pRight中
root.Right = nil // 删除传入节点的右子树
return pRight // 返回传入节点的右子树
}
// 若传入节点的左孩子不为空
root.Left = deleteNode1(root.Left) // 向左搜索
return root
}
|
Link
GitHub