Binary Search Tree (BST) 的增刪查 -1
Binary Search Tree (BST) 的增刪查
Binary Search Tree (BST)的目的是方便搜尋,特點是一個節點(node)左邊的value比節點的值小,右邊的value比節點的值大或者等於。
首先需要定義一個單獨的節點類
class BST:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
這裡一個節點包含三個部分: 本身的value 左邊的child 右邊的child
child可以是單獨的節點、一個子樹, 也可以為空。
以下增刪查的部分按照難易程度排列:
增:插入 insert(self, value)
要插入一個值,首先要比較他和根節點的大小,然後根據“一個節點(node)左邊的value比節點的值小,右邊的value比節點的值大或者等於” 的規律進行左右搜尋,見“空”,新建節點並插入。
def insert(self, value): if value<self.value: if self.left is None: self.left = BST(value) else: self.left.insert(value) else: if self.right is None: self.right = BST(value) else: self.right.insert(value) return self
查:檢查是否包含 contains(self, value)
輸入一個值,返回當前BST中是否包含這個值,包含則返回True,否則返回False。
檢查是否包含一個值,依然是根據“一個節點(node)左邊的value比節點的值小,右邊的value比節點的值大或者等於” 的規律進行左右搜尋。
如果待查證的value小於當前節點值,向左繼續搜,如果此時左邊為空,返回False。
如果大於當前節點的值向右繼續搜,如果此時右邊為空,返回False。
如果待查證的value等於當前節點的值,返回True。
def contains(self, value): # Write your code here. if value<self.value: if self.left is None: return False else: self.left.contains(value) elif value>self.value: if self.right is None: return False else: self.left.contains(value) return True
刪:移除特定元素remove(self, value, parent = None)
刪除的操作比較複雜,因為要考慮很多的邊界條件。
在函式的引數表(self, value, parent = None)中給出了一個parent = None,意思是預設情況下該節點沒有父節點。
父節點十分重要,這涉及到如果移除當前節點,BST的值應當如何重新整理的問題。
假設有一棵樹:需要移除節點10(parent = None)
10
/ \
5 15
/ \ / \
2 5 13 22
/ / \
1 12 14
移除之後的結果是
12
/ \
5 15
/ \ / \
2 5 13 22
/ \
1 14
此時節點右側的最小值,也就是將右側的子樹一直向右搜尋出來的值將會取代當前節點的值,並且這個搜出來的右側最小值是大於左側所有值的最小值。因為左邊的值只能是越來越小,右邊即使最小的值也應該比左邊任意一個值大。
此時給出另一種刪除的情形,不是刪除根節點(parent is not None)
刪除15,parent = 10(此時這個節點有parent父節點):
結果是:
10
/ \
5 14
/ \ / \
2 5 13 22
/ / \
1 12
此時要將當前節點中左側子樹,也就是比當前節點都要小的值中,最大的值拿出來。原因是必須保證這個用來替換的值大於左邊的任何一個值,還要小於等於右邊的任何一個值。
接著,當前節點的parent的右邊的節點就是當前節點(值被替換後)
def remove(self,value,parent = None):
if value<self.value:
#比當前值小,左邊非空,迭代演算法
if self.left is not None:
#注意此時的self是當前節點,也就是下一個節點的parent
self.left.remove(value,parent = self)
if value>self.value:
#比當前值大,右邊非空,迭代演算法
if self.left is not None:
self.left.remove(value,parent = self)
#注意此時的self是當前節點,也就是下一個節點的parent
else: #考慮此時當前值相等的情況
#如果兩邊都有東西,當前值是右側子樹的最小值,並移除該值對應的節點。
#此時已經考慮節點的兩邊都有子樹的情況
if self.left is not None and self.right is not None:
self.value = self.right.getMin(self)
self.right.remove(self.value)
#如果當前節點沒有父節點,意味著當前節點是根節點。
#考慮此時根節點只有一邊有子樹的情況
elif parent is None:
# 如果左邊不是空的
if self.left is not None:
self.value = self.left.value
self.right = self.left.right
self.left = self.left.left
# 如果右邊不是空的
elif self.right is not None:
self.value = self.right.value
self.left = self.right.left
self.right = self.right.right
else:
pass
elif parent.left == self:
parent.left = self.left if self.left is not None else self.right
elif parent.right == self:
parent.right = self.left if self.left is not None else self.right
return self
- 獲取當前BST最小值 getMin(self)
獲取最小值的方法比較簡單,就是一直向左迭代搜尋,直到搜尋到當前節點的左側沒有節點位置(也就是沒有值比當前節點的值更小了)。
def getMin(self):
if self.left is None:
return self.value
else:
self.left.getMin(value)