二叉查找樹(Binary Search Tree),又稱爲二叉搜索樹,二叉排序樹。它能夠是一棵空樹,若是不是空樹,則具備下列的性質:python
好比下面兩棵樹,左邊的樹,由於5小於10,應該在10的左子樹上,所以不是二叉查找樹,右邊的樹則符合二叉查找樹的條件。 算法
二叉查找樹的查找過程,能夠分爲下面的步驟:優化
下圖以查找33爲例,展現了查找的軌跡spa
def find(root: TreeNode, key):
if not root:
return None
if key == root.val:
return root
elif key < root.val:
return find(root.left, key)
else:
return find(root.right, key)
複製代碼
固然,上面的遞歸算法中存在尾遞歸,通常的編譯器都會自動優化尾遞歸,咱們也能夠將代碼改成迭代的方式3d
def find(root: TreeNode, key):
if not root:
return None
while root:
if key == root.val:
return root
elif key < root.val:
root = root.left
else:
root = root.right
複製代碼
能夠看的出來,算法的複雜度和樹的高度有關,每一次對比以後都會捨棄掉原來數據的一半,所以算法的時間複雜爲O(logn)code
根據二叉查找樹的性質:cdn
def findMax(root: TreeNode):
if root:
while root.right:
root = root.right
return root
def findMin(root: TreeNode):
if root:
while root.left:
root = root.left
return root
複製代碼
因爲二叉查找樹具備特定的性質,所以在插入新的結點的時候,也要保證二叉查找樹的性質,整個插入新結點的過程與查找的過程相似,blog
以插入35爲例,下圖展現了插入35的軌跡 排序
def insert(root: TreeNode, key):
if not root:
return TreeNode(key) # 若是是空樹,則新建根結點
while root:
if key == root.val:
break # 若是插入的key已經存在,則直接退出循環
elif key < root.val:
# 小於向左子樹查找
if not root.left:
root.left = TreeNode(key)
else:
root = root.left
else:
# 大於向右子樹查找
if not root.right:
root.right = TreeNode(key)
else:
root = root.right
return root
複製代碼
刪除操做比較複雜,要分狀況談論:遞歸
這種狀況下,直接刪除。以下圖要刪除35結點
這種狀況下,直接將要刪除結點的孩子結點,向上提,替代要刪除的結點,以下圖要刪除33結點
這種狀況下,能夠有兩種方案:
若是要刪除41結點(使用左子樹最大元素代替)
左子樹的最大元素,依舊比右子樹的全部元素小,可是比其餘左子樹的元素大,所以它成爲新的根結點的時候,依舊能保持左子樹下的全部元素比根結點小,右子樹下的全部元素比根結點大。
若是要刪除41結點(使用右子樹最小元素代替)
右子樹的最小元素,依舊比左子樹的全部元素大,可是比其餘右子樹的元素小,成爲新的根結點,依舊能保持二叉查找樹的性質
綜合上面的狀況,代碼以下
def delete(root: TreeNode, key):
if not root:
return None
if key < root.val:
root.left = delete(root.left, key)
elif key > root.val:
root.right = delete(root.right, key)
else:
if root.left and root.right:
# 有左右孩子
leftMax = findMax(root.left)
root.val = leftMax.val
root.left = delete(root.left, leftMax.val)
elif not root.left and not root.right:
# 葉子結點
root = None
elif root.left:
# 只有左孩子
root = root.left
elif root.right:
# 只有右孩子
root = root.right
return root
複製代碼
在有左右孩子的狀況下,實際上只是把替代結點的值賦值給要刪除結點的值,真正刪除的是原來的替代結點,好比要刪除41結點,替代結點爲35,則把41改成35,而後刪除原來的35結點。
二叉查找樹將數據按照順序組織好,排列成二叉樹結構,所以相關算法的複雜度基本取決於樹的高度,若是在構建二叉查找樹的時候,不注意樹的高度,容易構建成一棵斜樹,這樣二叉查找樹就失去了優點。
二叉查找樹有較高的插入和刪除效率,而且具有較高的查找效率,對組織動態數據比較友好。
Thanks!