二叉查找树(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!