二叉搜索树(Binary Search Tree)
什么是 Binary Search Tree (BST)?
二叉搜索树 (Binary Search Tree, 简称 BST) 是一种二叉树,其特点是节点按一定的顺序排列,便于快速查找、插入和删除。具体定义如下:
- 每个节点有一个值。
- 对于每个节点,其左子树中的所有节点值都小于该节点的值。
- 对于每个节点,其右子树中的所有节点值都大于该节点的值。
- 每个子树本身也是一个二叉搜索树。
BST 的特性
- 有序性:通过中序遍历 (in-order traversal) 可以得到从小到大的排序结果。
- 动态性:BST 可以随时插入或删除节点,并保持其结构的正确性。
- 高效性:在理想情况下(树是平衡的),查找、插入和删除的时间复杂度为 。
性能
BST 的性能依赖于树的高度:
- 平衡 BST(如 AVL 树或红黑树)的高度为 ,操作性能良好。
- 如果输入数据有序,普通 BST 可能会退化成链表,操作时间复杂度变为 。
应用
- 动态集合操作:如查找、插入、删除等。
- 排序:通过中序遍历得到有序序列。
- 实现符号表:在编译器、数据库等场景中存储和查找键值对。
- 范围查询:快速找到值在某个范围内的所有节点。
总结
二叉搜索树是一种高效的数据结构,适用于动态数据集的管理。然而,普通 BST 在数据不均匀分布时可能会退化,因此在实际应用中,常结合平衡技术(如红黑树、AVL 树)以提升性能。
二叉搜索树的操作
在 LeetCode 中,涉及 Binary Search Tree (BST) 的题目主要围绕查找、插入、删除、遍历,以及与树结构相关的高级应用。这些题目可以帮助理解和练习 BST 的基本操作及优化方法。以下是相关操作和典型题目分类:
1. 查找操作
核心思路:
- 从根节点开始,根据值的大小决定递归进入左子树或右子树。
- 如果找到值则返回对应节点或
True
,未找到则返回False
。
示例题目:
- LeetCode 700: Search in a Binary Search Tree
- 描述:在 BST 中查找值等于
target
的节点,返回该节点的子树。 - 代码:
def searchBST(root, val):
if not root or root.val == val:
return root
return searchBST(root.left, val) if val < root.val else searchBST(root.right, val)
- 描述:在 BST 中查找值等于
2. 插入操作
核心思路:
- 从根节点开始,递归找到适当位置插入新节点,同时保持 BST 的有序性。
示例题目:
- LeetCode 701: Insert into a Binary Search Tree
- 描述:向 BST 中插入一个新的值,返回修改后的树。
- 代码:
def insertIntoBST(root, val):
if not root:
return TreeNode(val)
if val < root.val:
root.left = insertIntoBST(root.left, val)
else:
root.right = insertIntoBST(root.right, val)
return root
3. 删除操作
核心思路:
删除一个节点时,需要处理以下几种情况:
- 节点为叶子节点,直接删除。
- 节点只有一个子节点,用子节点代替当前节点。
- 节点有两个子节点,用中序后继或中序前驱替代当前节点的值,然后删除该替代节点。
示例题目:
- LeetCode 450: Delete Node in a BST
- 描述:删除 BST 中指定的节点,返回修改后的树。
- 代码:
def deleteNode(root, key):
if not root:
return None
if key < root.val:
root.left = deleteNode(root.left, key)
elif key > root.val:
root.right = deleteNode(root.right, key)
else:
if not root.left:
return root.right
if not root.right:
return root.left
# Find in-order successor
successor = root.right
while successor.left:
successor = successor.left
root.val = successor.val
root.right = deleteNode(root.right, successor.val)
return root
4. 遍历操作
BST 遍历通常涉及:
- 中序遍历:按升序排列输出所有节点。
- 前序遍历:在构建树或序列化时常用。
- 后序遍历:在删除操作中可能有用。
示例题目:
- LeetCode 94: Binary Tree Inorder Traversal
- 描述:返回树的中序遍历。
- 代码:
def inorderTraversal(root):
return inorderTraversal(root.left) + [root.val] + inorderTraversal(root.right) if root else []
5. 验证 BST
核心思路:
通过递归检查每个节点是否满足 BST 的性质:左子树的最大值 < 当前节点 < 右子树的最小值。
示例题目:
- LeetCode 98: Validate Binary Search Tree
- 描述:判断一棵树是否是 BST。
- 代码:
def isValidBST(root, low=float('-inf'), high=float('inf')):
if not root:
return True
if not (low < root.val < high):
return False
return isValidBST(root.left, low, root.val) and isValidBST(root.right, root.val, high)
6. 查找 Kth Smallest/Largest 元素
核心思路:
利用中序遍历可以得到有序的节点列表,从中直接定位第 K 小/大的元素。
示例题目:
- LeetCode 230: Kth Smallest Element in a BST
- 描述:返回 BST 中第 K 小的元素。
- 代码:
def kthSmallest(root, k):
stack = []
while True:
while root:
stack.append(root)
root = root.left
root = stack.pop()
k -= 1
if k == 0:
return root.val
root = root.right
7. 最近公共祖先 (LCA)
核心思路:
在 BST 中,最近公共祖先是两个节点路径上最后一个分叉点。
示例题目:
- LeetCode 235: Lowest Common Ancestor of a Binary Search Tree
- 描述:找到两个节点的最近公共祖先。
- 代码:
def lowestCommonAncestor(root, p, q):
if root.val > p.val and root.val > q.val:
return lowestCommonAncestor(root.left, p, q)
elif root.val < p.val and root.val < q.val:
return lowestCommonAncestor(root.right, p, q)
return root
8. 范围查询
核心思路:
递归遍历节点时,只处理值在范围内的节点。
示例题目:
- LeetCode 938: Range Sum of BST
- 描述:计算 BST 中所有值在
[low, high]
范围内的节点值之和。 - 代码:
def rangeSumBST(root, low, high):
if not root:
return 0
if root.val < low:
return rangeSumBST(root.right, low, high)
elif root.val > high:
return rangeSumBST(root.left, low, high)
return root.val + rangeSumBST(root.left, low, high) + rangeSumBST(root.right, low, high)
- 描述:计算 BST 中所有值在
9. 构建树
示例题目:
- LeetCode 108: Convert Sorted Array to Binary Search Tree
- 描述:将有序数组转换为高度平衡的 BST。
- 代码:
def sortedArrayToBST(nums):
if not nums:
return None
mid = len(nums) // 2
root = TreeNode(nums[mid])
root.left = sortedArrayToBST(nums[:mid])
root.right = sortedArrayToBST(nums[mid+1:])
return root
总结
在 LeetCode 中,BST 的操作题目涵盖了:
- 基础操作:查找、插入、删除。
- 辅助功能:验证 BST、查找第 K 小值、最近公共祖先等。
- 高级应用:范围查询、构建树、平衡树操作。
通过练习这些题目,可以深入理解 BST 的性质及其高效操作。