2022-12-07 23:25阅读: 50评论: 0推荐: 0

二叉查找树

二叉搜索树

定义

一棵二叉查找树BST)是一个二叉树,其中每个结点都含有一个Camparable的键(以及相关联的值)且每个结点的键都大于其左子树中的任意结点的键,而小于右子树的任意结点的键。

性质

二叉查找树具有以下性质:

  • 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  • 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  • 任意节点的左、右子树也分别为二叉查找树;
  • 没有键值相等的节点。

常用结论

二叉查找树的中序遍历的结果是一个升序序列。

二叉树的常用操作

这里,我们直接给出二叉查找树的校验插入查找删除操作的模板,模板分为递归实现和迭代实现两种。

二叉查找树的有效性校验

递归的思路

递归的时候,我们只需要将问题分解为子问题,即考虑如何判断每一个子节点的有效性即可。

直接根据性质,对于任意一个结点 root,需要要保证 root 节点的值:

  • 大于其左节点的值,还要小于其右节点的值;
  • 大于左子树上的每一个节点值,同时,小于右子树上每一个节点的值。

那么,我们定义一个 validate(root,minnode,maxnode) 函数,递归的时候,将当前节点的通过参数 min_node 将其传给右子树,通过参数 max_node 将其传给右子树,让每个节点依次与其比较,不满足条件,直接返回 False

迭代的思路

由于二叉查找树的中序遍历得到的是一个升序数组,所以,可以通过栈模拟二叉树的中序遍历,比较每次记录出栈的元素是否是升序的即可。

二叉查找树的查找

二叉查找树的查找比较简单,直接利用BST左小右大的性质,进行二分搜索即可。

查找最大值

查找最大值,一路查找右子树即可。

查找最小值

查找最小值,一路查找左子树即可。

二叉查找树的插入

递归的思路

递归遍历一棵BST,找到一个合适的位置,将原有的空节点替换为新插入的节点即可。

递归的时候,由于需要通过返回值返回子树,所以不能判断待插入的节点是否以及在原有的BST上。

迭代的思路

递归遍历一棵BST,找到一个合适的位置,将原有的空节点替换为新插入的节点即可。

迭代过程中,可以判断待插入的节点是否在原有的BST上。

二叉查找树的删除

二叉查找树的删除,需要考虑三种情况:

  • 场景1:待删除的节点是叶子节点,直接删除该节点即可;
  • 场景2:待删除的节点有一个子节点,删除该节点后,将父节点的指针指向子节点;
  • 场景2:待删除的节点有两个子节点,用左子树的最大节点,或者右子树的最小节点,替换待删除的节点。

代码实现

具体代码实现,如下:

递归实现

class Node(object):
def __init__(self, value, left=None, right=None):
self.left = left
self.right = right
self.value = value
def __str__(self):
return str(self.value)
class BST(object):
@classmethod
def is_valid(cls, root: Node) -> bool:
return cls.validate(root, None, None)
@classmethod
def validate(cls, root: Node, min_node: Node, max_node: Node) -> bool:
""" 判断以root为根节点的子树是否是BST
:param root: 根节点
:param min_node: 以root为根节点的子树中的最小节点
:param max_node: 以root为根节点的子树中的最大节点
:return: 结果
"""""
if not root:
return True
if min_node and root.value <= min_node.value:
return False
if max_node and root.value >= max_node.value:
return False
return cls.validate(root.left, min_node, root) and cls.validate(root.right, root, max_node)
@classmethod
def find(cls, value: int, tree: Node):
if not tree:
return None
if value < tree.value:
return cls.find(value, tree.left)
elif value > tree.value:
return cls.find(value, tree.right)
else:
return tree
@classmethod
def find_min(cls, tree: Node):
if not tree:
return None
if tree.left is None:
return tree
else:
return cls.find_min(tree.left)
@classmethod
def find_max(cls, tree: Node):
if not tree:
return None
if tree.right is None:
return tree
else:
return cls.find_max(tree.right)
@classmethod
def insert(cls, root: Node, target: int):
if not root:
return Node(target)
if root.value < target:
root.right = cls.insert(root.right, target)
if root.value > target:
root.left = cls.insert(root.left, target)
return root
@classmethod
def delete(cls, root: Node, target: int):
if not root:
return None
if root.key > target:
root.left = cls.delete(root.left, target)
elif root.key < target:
root.right = cls.delete(root.right, target)
else:
if not root.left:
return root.right
if not root.right:
return root.left
# 找到左子树的最大值,或者,找到右子树的最小值
min_node = cls.find_min(root.right)
root.key = min_node.key
# 删掉min节点
root.right = cls.delete(root.right, min_node.key)
return root

迭代实现

class Node(object):
def __init__(self, value, left=None, right=None):
self.left = left
self.right = right
self.value = value
def __str__(self):
return str(self.value)
class BST(object):
@classmethod
def is_valid(cls, root: Node) -> bool:
stack, inorder = [], float('-inf')
while stack or root:
while root:
stack.append(root)
root = root.left
root = stack.pop()
if root.value <= inorder:
return False
inorder = root.value
root = root.right
return True
@classmethod
def find(cls, value: int, tree: Node):
""" 非递归查找指定的节点 """
if not tree:
return None
while True:
if value < tree.value:
tree = tree.left
elif value > tree.left:
tree = tree.right
else:
break
return tree
@classmethod
def find_min(cls, tree: Node):
""" 非递归查找最小值的节点 """
if not tree:
return None
while tree.left:
tree = tree.left
return tree
@classmethod
def find_max(cls, tree: Node):
""" 非递归查找最大值的节点 """
if not tree:
return None
while tree.right:
tree = tree.right
return tree
@classmethod
def insert(cls, root: Node, target: int) -> bool:
if not root:
return False
# 先找到一个合适的位置
parent = None
while root:
if root.value == target:
return False
else:
parent = root
if root.value > target:
root = root.left
else:
root = root.right
# 插入到子节点
if parent.value < target:
parent.right = Node(target)
else:
parent.left = Node(target)
return True
@classmethod
def delete(cls, root: Node, key: int):
# 找到待删除的节点,及其父节点
deleted_node, delete_node_parent = root, None
while deleted_node and deleted_node.value != key:
delete_node_parent = deleted_node
if deleted_node.value > key:
deleted_node = deleted_node.left
else:
deleted_node = deleted_node.right
# 待删除的节点为空直接返回
if deleted_node is None:
return root
# 叶子节点直接删除
if deleted_node.left is None and deleted_node.right is None:
deleted_node = None
# 如果只有一个子节点,就用子节点覆盖待删除的节点
elif deleted_node.right is None:
deleted_node = deleted_node.left
elif deleted_node.left is None:
deleted_node = deleted_node.right
# 如果有两个子节点
else:
# 找到待删除节点的右子树的最小值
successor, successor_parent = deleted_node.right, deleted_node
while successor.left:
successor_parent = successor
successor = successor.left
if successor_parent.value == deleted_node.value:
successor_parent.right = successor.right
else:
successor_parent.left = successor.right
successor.right = deleted_node.right
successor.left = deleted_node.left
deleted_node = successor
if delete_node_parent is None:
return deleted_node
if delete_node_parent.left and delete_node_parent.left.value == key:
delete_node_parent.left = deleted_node
else:
delete_node_parent.right = deleted_node
return root

本文作者:LARRY1024

本文链接:https://www.cnblogs.com/larry1024/p/16964745.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   LARRY1024  阅读(50)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.