步骤
1. 寻找节点的父节点,有三种情况:
- 目标节点即根节点
- 目标节点非根节点
- 目标节点不存在
2. 删除节点
- 如果目标节点是根节点:
将根节点左子树移到右子树最左侧,返回右子树 - 如果目标节点非根节点:
- 如果目标节点没有右子树,直接父节点对应指针指向左子树,返回树
- 如果目标节点有右子树,将左子树移到右子树最左侧,父节点对应指针指向右子树,返回树
- 目标节点不存在,返回树
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func deleteNode(root *TreeNode, key int) *TreeNode {
if root == nil {
return root
}
// 寻找目标节点的父节点位置,并标记目标节点是父节点的左还是右,0左1右,-1表示节点不存在, -2表示目标是根
preNode,flags := findNode(root,key)
if flags == -1{
return root
}else if flags == -2 {
if preNode.Left != nil && preNode.Right != nil {
rln := preNode.Right
for rln.Left != nil {
rln = rln.Left
}
rln.Left = preNode.Left
return preNode.Right
}
if preNode.Left != nil {
return preNode.Left
}else{
return preNode.Right
}
}
// 获取目标节点
var node *TreeNode
if flags == 0{
node = preNode.Left
}else if flags == 1 {
node = preNode.Right
}else{
return root
}
// 按目标左右节点分布情况决定如何删除目标节点
ln := node.Left
rn := node.Right
// 1. 没有左右节点, 直接删除
if ln == nil && rn == nil {
if flags == 0{
preNode.Left = nil
}else if flags == 1 {
preNode.Right = nil
}
return root
}
// 2. 只有左子节点,左子节点顶替目标节点
if ln != nil && rn == nil {
if flags == 0{
preNode.Left = ln
}else if flags == 1 {
preNode.Right = ln
}
return root
}
// 3. 只有右子节点,右子节点顶替目标节点
if ln == nil && rn != nil {
if flags == 0{
preNode.Left = rn
}else if flags == 1 {
preNode.Right = rn
}
return root
}
// 4. 左右节点都存在
if ln != nil && rn != nil {
// 左子树加入右子树,放在右子树最左侧
rnl := rn
for rnl.Left!=nil {
rnl= rnl.Left
}
rnl.Left = ln
// 右子节点顶替目标节点
if flags == 0{
preNode.Left = rn
}else if flags == 1 {
preNode.Right = rn
}
return root
}
return root
}
func findNode(root *TreeNode, key int) (*TreeNode,int) {
if root.Val == key{return root,-2}
var pre *TreeNode
for {
if key > root.Val {
if root.Right != nil {
pre = root
root = root.Right
continue
}else{
return nil,-1
}
}
if key < root.Val {
if root.Left != nil {
pre = root
root = root.Left
continue
}else{
return nil,-1
}
}
if root == pre.Left{
return pre,0 // 左子节点
}else{
return pre,1 // 右子节点
}
}
}
代码还能简化…