二叉查找树
二叉搜索树
定义
一棵二叉查找树(
性质
二叉查找树具有以下性质:
- 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
- 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
- 任意节点的左、右子树也分别为二叉查找树;
- 没有键值相等的节点。
常用结论
二叉查找树的中序遍历的结果是一个升序序列。
二叉树的常用操作
这里,我们直接给出二叉查找树的校验、插入、查找、删除操作的模板,模板分为递归实现和迭代实现两种。
二叉查找树的有效性校验
递归的思路
递归的时候,我们只需要将问题分解为子问题,即考虑如何判断每一个子节点的有效性即可。
直接根据性质,对于任意一个结点
- 大于其左节点的值,还要小于其右节点的值;
- 大于左子树上的每一个节点值,同时,小于右子树上每一个节点的值。
那么,我们定义一个
迭代的思路
由于二叉查找树的中序遍历得到的是一个升序数组,所以,可以通过栈模拟二叉树的中序遍历,比较每次记录出栈的元素是否是升序的即可。
二叉查找树的查找
二叉查找树的查找比较简单,直接利用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 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步