今天講二元樹的刪除,特別拉一篇出來講,是因為它滿複雜,要處理的case很多。
樹的刪除這邊會把它分成4個case
刪45,45的左右child都為空,直接把30的右child改為空
刪14,14有左child但沒有右child,把1拉上去,30的左child接到1
刪45,45有右child 60,但60底下沒有左child,那就把60拉上去,60的左child接38,30的右child接60
這時候的情境比較複雜,我們需要找右邊child底下最小的值,往右邊child的左child做搜尋,找到最小的值。大家可以試試看如果用54或73做替換,再用樹搜尋一下51,你會發現二元樹的特性被破壞,導致有些值永遠找不到。
刪45,右child不為空,而且60擁有左child,往左child找最小值,找到51,把51拉上來,58的左child接到54,51的左child接38 右child接60,30的右child接51。
4個case都講完了,就可以轉化為程式
這邊會做leetcode的450題,leetcode有大量test case,如果都過了就證明沒問題~
Leetcode #450. Delete Node in a BST
程式
func deleteNode(root *TreeNode, key int) *TreeNode {
var preNode *TreeNode
currentNode := root
// 先找到要刪的節點
for {
// 找不到
if currentNode == nil {
return root
}
if currentNode.Val == key {
break
}
if key < currentNode.Val {
// 往左找
preNode = currentNode
currentNode = currentNode.Left
} else {
// 往右找
preNode = currentNode
currentNode = currentNode.Right
}
}
// case.1 左右chil為空
if currentNode.Left == nil && currentNode.Right == nil {
// 刪的是root節點
if preNode == nil {
root = nil
return root
}
if currentNode.Val < preNode.Val {
preNode.Left = nil
} else {
preNode.Right = nil
}
return root
}
// case.2 左child有東西 右child為空
if currentNode.Left != nil && currentNode.Right == nil {
// 刪的是root節點
if preNode == nil {
root = currentNode.Left
return root
}
// 判斷要接到上一個節點的左邊還是加邊
if currentNode.Val < preNode.Val {
preNode.Left = currentNode.Left
} else {
preNode.Right = currentNode.Left
}
return root
}
// case.3 右child有東西 但它沒有左child
if currentNode.Right != nil && currentNode.Right.Left == nil {
// 把目前節點的左child 接到右child的左child
currentNode.Right.Left = currentNode.Left
// 刪的是root節點
if preNode == nil {
root = currentNode.Right
return root
}
// 判斷要接到上一個節點的左邊還是加邊
if currentNode.Val < preNode.Val {
preNode.Left = currentNode.Right
} else {
preNode.Right = currentNode.Right
}
return root
}
// case.4 右child擁有左child
// 從左child開始找 找到最小的值
leftMostParent := currentNode.Right
leftMost := currentNode.Right.Left
for leftMost.Left != nil {
leftMostParent = leftMost
leftMost = leftMost.Left
}
leftMostParent.Left = leftMost.Right
leftMost.Left = currentNode.Left
leftMost.Right = currentNode.Right
// 刪的是root節點
if preNode == nil {
root = leftMost
return root
}
if leftMost.Val < preNode.Val {
preNode.Left = leftMost
} else {
preNode.Right = leftMost
}
return root
}
Runtime: 12 ms, faster than 86.46% of Go online submissions for Delete Node in a BST.
Memory Usage: 7.1 MB, less than 96.88% of Go online submissions for Delete Node in a BST.
大家在leetcode的soultion可以找到非常簡潔的做法,有興趣可以上去看,不過更不好理解就是了XD
終於講完二元樹的新增刪除走訪了QQ
鏈結的概念一定要先搞懂,不然樹會很難理解
今天先這樣~Bye~~