二叉搜索树(BST)
(1)别名:二叉查找树、二叉搜索树。
(2)根节点的值大于其左子树中任意一个节点的值,小于其右节点中任意一个节点的值。
(3)BST的中序序列一定是升序的
(4)二叉搜索树的操作:查询、插入、删除
二叉搜索树的插入
首先检查树是否有根。如果没有根,那么 insert 将创建一个新的 TreeNode 并将其做为树的根。如果根节点已经就位,则 insert 调用私有递归辅助函数 insert根据以下流程搜索树:
(1)从树的根开始,搜索二叉树,将新键与当前节点中的键进行比较。如果新键小于当前节点,则搜索左子树。如果新键大于当前节点,则搜索右子树。
(2)当没有左(或右)孩子要搜索时,我们在树中找到应该建立新节点的位置。
(3)向树中添加节点时,先创建一个新的 BiTreeNode对象,并将对象插入到上一步发现的节点。插入时,总是作为叶节点插入到树中。
给定序列去依次构造二叉查找树,则二叉搜索树唯一;如果是用这个序列所有的关键字去构造可能的二叉树(排列任意),则一般不唯一。
二叉搜索树的查询
当二叉查找树不为空时:
(1)首先将给定值与根结点的关键字比较,若相等,则查找成功
(2)若小于根结点的关键字值,递归查左子树
(3)若大于根结点的关键字值,递归查右子树
(4)若子树为空,查找不成功
二叉搜索树的删除
第一个任务是通过搜索树来找到要删除的节点。 如果树具有多个节点,我们使用 query方法搜索以找到需要删除的 BiTreeNode。 如果树只有一个节点,这意味着我们删除树的根,但是我们仍然必须检查以确保根的键匹配要删除的键。 在任一情况下,如果未找到键,del 操作符将引发错误。
一旦我们找到了我们要删除的键的节点,我们必须考虑三种情况:
(1)要删除的节点没有子节点。
(2)要删除的节点只有一个子节点。
(3)要删除的节点有两个子节点。
第一种情况:
如果当前节点没有子节点,我们需要做的是删除节点并删除对父节点中该节点的引用。
第二种情况:
如果一个节点只有一个孩子,那么我们可以简单地将孩子取代其父。一般我们有六种情况要考虑。由于这些情况相对于左孩子或右孩子对称,我们将仅讨论当前节点具有左孩子的情况。决策如下:
如果当前节点是左子节点,则我们只需要更新左子节点的父引用以指向当前节点的父节点,然后更新父节点的左子节点引用以指向当前节点的左子节点。
如果当前节点是右子节点,则我们只需要更新左子节点的父引用以指向当前节点的父节点,然后更新父节点的右子节点引用以指向当前节点的左子节点。
如果当前节点没有父级,则它是根。在这种情况下,我们将通过在根上调用replaceNodeData 方法来替换 key,payload,leftChild 和 rightChild 数据。
第三种情况:
最难处理的情况。 如果一个节点有两个孩子,那么我们不太可能简单地提升其中一个节点来占据节点的位置。 然而,我们可以在树中搜索可用于替换被调度删除的节点的节点。 我们需要的是一个节点,它将保留现有的左和右子树的二叉搜索树关系。 执行此操作的节点是树中具有次最大键的节点。 我们将这个节点称为后继节点,我们将看一种方法来很快找到后继节点。 继承节点保证没有多于一个孩子,所以我们知道使用已经实现的两种情况删除它。 一旦删除了后继,我们只需将它放在树中,代替要删除的节点。找到后继的代码如下所示,是BiTreeNode 类的一个方法。
一般我们利用BST的特性:中序遍历是升序。因此采用中序遍历从最小到最大打印树中的节点。在寻找接班人时,有三种情况需要考虑:
如果节点有右子节点,则后继节点是右子树中的最小的键。
如果节点没有右子节点并且是父节点的左子节点,则父节点是后继节点。
如果节点是其父节点的右子节点,并且它本身没有右子节点,则此节点的后继节点是其父节点的后继节点,不包括此节点。
参考:https://www.php.cn/python-tutorials-412354.html
总结:删除操作——先中序遍历,然后把删除节点的前继和后继提上去
"""
======================
-*- coding: utf-8 -*-
@author: Qiufen.Chen
@time: 2021/7/24:22:28
@email: 1760812842@qq.com
@File: bst.py
@Project: data_structure
======================
"""
"""二叉搜索树(BST)的操作"""
# 定义二叉树
class BiTreeNode:
def __init__(self,data):
self.data = data
self.lchild = None # 左孩子
self.rchild = None # 右孩子
self.parent = None
class BST:
def __init__(self, li=None):
self.root = None
if li:
for val in li:
self.insert_no_cur(val)
# 递归插入
def insert(self, node, val):
if not node:
node = BiTreeNode(val)
elif val < node.data:
node.lchild = self.insert(node.lchild, val)
node.lchild.parent = node
elif val > node.data:
node.rchild = self.insert(node.rchild, val)
node.rchild.parent = node
return node
# 非递归插入
def insert_no_cur(self, val):
p = self.root
if not p:
self.root = BiTreeNode(val)
return
while True:
if val < p.data:
if p.lchild:
p = p.lchild
else:
p.lchild = BiTreeNode(val)
p.lchild.parent = p
return
elif val > p.data:
if p.rchild:
p = p.rchild
else:
p.rchild = BiTreeNode(val)
p.rchild.parent = p
return
else:
return
# 递归查找
def query(self, node, val):
if not node:
return None
if node.data < val:
return self.query(node.rchild, val)
elif node.data > val:
return self.query(node.lchild, val)
else:
return node
# 非递归查找
def query_no_rec(self, val):
p = self.root
while p:
if p.data < val:
p = p.rchild
elif p.data > val:
p = p.lchild
else:
return p
return None
def _remove_node_1(self,node):
# 情况1:node是叶子结点
if not node.parent:
self.root = None
if node == node.parent.lchild: # node是它父亲的左孩子
node.parent.lchild = None
else: # 右孩子
node.parent.rchild = None
def _remove_node_21(self, node):
# 只有一个左孩子
if not node.parent:
self.root = node.lchild
node.lchild.parent = None
elif node == node.parent.lchild:
node.parent.lchild = node.lchild
node.lchild.parent = node.parent
else:
node.parent.rchild = node.lchild
node.lchild.parent = node.parent
def _remove_node_22(self, node):
# 只有一个右孩子
if not node.parent:
self.root = node.rchild
elif node == node.parent.lchild:
node.parent.lchild = node.rchild
node.rchild.parent = node.parent
else:
node.parent.rchild = node.rchild
node.rchild.parent = node.parent
def delete(self, val):
if self.root: # 不是空树
node = self.query_no_rec(val) # 找不到返回None
if not node: # 不存在
return False
if not node.lchild and not node.rchild: # 1. 叶子结点
self._remove_node_1(node)
elif not node.rchild: # 2.1 只要一个左孩子
self._remove_node_21(node)
elif not node.lchild: # 2.2 只有一个右孩子
self._remove_node_22(node)
else:
# 3.两个孩子都有
min_node = node.rchild
while min_node.lchild:
min_node = min_node.lchild
node.data = min_node.data
# 删除min_node
if min_node.lchild:
self._remove_node_22(min_node)
else:
self._remove_node_1(min_node)
# 二叉树的中序遍历
def in_order(self, root):
if root:
self.in_order(root.lchild)
print(root.data, end=',')
self.in_order(root.rchild)
if __name__=="__main__":
tree = BST([4,6,7,9,2,1,3,5,8])
tree.in_order(tree.root)
print("")
tree.delete(6)
tree.in_order(tree.root)