数据结构之树(二叉搜索树)
二叉搜索树
二叉搜索树(Binary Search Tree,BST)是一种基本的数据结构,用于存储和管理有序数据集。它是一种树状结构,其中每个节点都包含一个值,且满足以下性质:
- 左子树中的所有节点的值都小于或等于该节点的值。
- 右子树中的所有节点的值都大于该节点的值。
这些性质保证了二叉搜索树的有序性,使得在树中查找、插入和删除操作都可以在平均情况下在O(log n)时间内完成,其中n是树中节点的数量。
然而,最坏情况下,BST可能退化为链表,导致操作的时间复杂度为O(n)。
为了解决这个问题,二叉搜索树的一种变种是二次搜索树(Balanced Binary Search Tree),也称为自平衡二叉搜索树。这些树具有额外的性质,以确保它们的高度保持较小的范围,从而保持操作的平均时间复杂度为O(log n)。
常见的二次搜索树包括:
-
AVL树:AVL树是一种自平衡二叉搜索树,通过维护节点的平衡因子来确保树的高度差不超过1。当插入或删除节点时,AVL树会自动调整以恢复平衡。
-
红黑树:红黑树也是一种自平衡二叉搜索树,通过规定节点的颜色和一些规则来保持平衡。它的性能非常稳定,适用于大多数情况。
-
Splay树:Splay树是一种自平衡二叉搜索树,它通过在每次访问节点时将其移动到根节点来保持平衡。这使得最常访问的节点保持在靠近根的位置,提高了操作的效率。
-
Treap:Treap是一种结合了二叉搜索树和堆(heap)性质的自平衡树,节点具有键值和随机的优先级值。它通过维护这两个属性来保持平衡。
这些二次搜索树的选择取决于应用的具体需求和性能要求。它们在不同情况下都表现出不同的性能特点,因此需要根据具体情况选择合适的数据结构。
1. 自平衡二叉搜索树 (Balanced Binary Search Tree): 自平衡二叉搜索树是一种特殊类型的二叉搜索树,它确保树的高度始终保持在较小范围内,从而保持了查找、插入和删除操作的平均时间复杂度为 O(log n)。这些树根据节点之间的平衡特性来维护其结构,以避免退化成链表。
2. 最佳实践: 选择自平衡二叉搜索树时,通常可以考虑以下几种常见的选项:
-
AVL树:AVL树通过维护节点的平衡因子(左子树高度与右子树高度之差)来保持平衡。在大多数情况下,AVL树是一个很好的选择,但它的平衡维护可能需要更多的旋转操作。
-
红黑树:红黑树是另一种常用的自平衡二叉搜索树,它通过节点的颜色属性和一组规则来保持平衡。红黑树的性能非常稳定,适用于许多应用场景。
-
Splay树:Splay树通过将最近访问的节点移动到根节点来保持平衡,以提高最常访问的节点的效率。这对于缓存和频繁访问相同数据的应用很有用。
-
Treap:Treap是一种结合了二叉搜索树和堆属性的自平衡树,节点具有键值和随机的优先级值。这种树在同时要求搜索和插入性能时可能很有用。
Python示例
自平衡二叉排序树-红黑树
from sortedcontainers import SortedDict # 创建一个红黑树 rb_tree = SortedDict() # 插入元素 rb_tree[3] = 'apple' rb_tree[1] = 'banana' rb_tree[5] = 'cherry' rb_tree[2] = 'date' # 查找元素 print(rb_tree[3]) # 输出 'apple' # 删除元素 del rb_tree[1] # 遍历树中的元素 for key, value in rb_tree.items(): print(key, value)
输出:
1 2 3 4 | apple 2 date 3 apple 5 cherry |
python自定义一个二叉搜索树
1. 二叉搜索树的实现:
在Python中,你可以使用类来实现二叉搜索树。每个节点(也是一个类)由一个值、左子节点和右子节点组成。
class TreeNode: def __init__(self, value): self.value = value self.left = None self.right = None class BinarySearchTree: def __init__(self): self.root = None
2. 插入操作:
要向BST中插入一个新节点,需要遵循BST的性质。递归地比较新节点的值与当前节点的值,并根据大小关系选择左子树或右子树进行插入。
def insert(self, value): if not self.root: self.root = TreeNode(value) else: self._insert(self.root, value) def _insert(self, node, value): if value < node.value: if node.left: self._insert(node.left, value) else: node.left = TreeNode(value) elif value > node.value: if node.right: self._insert(node.right, value) else: node.right = TreeNode(value)
3. 查找操作:
查找操作也是递归的。从根节点开始,与目标值进行比较,然后选择左子树或右子树来查找。
def find(self, value): return self._find(self.root, value) def _find(self, node, value): if not node: return False if value == node.value: return True elif value < node.value: return self._find(node.left, value) else: return self._find(node.right, value)
4. 删除操作:
删除节点涉及到多种情况,包括没有子节点、有一个子节点、有两个子节点等情况。这需要小心处理。你可以实现一个 _delete
方法,来处理这些情况。
5. 综合示例
class TreeNode: def __init__(self, value): self.value = value self.left = None self.right = None class BinarySearchTree: def __init__(self): self.root = None def insert(self, value): if not self.root: self.root = TreeNode(value) else: self._insert(self.root, value) def _insert(self, node, value): if value < node.value: if node.left: self._insert(node.left, value) else: node.left = TreeNode(value) elif value > node.value: if node.right: self._insert(node.right, value) else: node.right = TreeNode(value) def find(self, value): return self._find(self.root, value) def _find(self, node, value): if not node: return False if value == node.value: return True elif value < node.value: return self._find(node.left, value) else: return self._find(node.right, value) bst = BinarySearchTree() bst.insert(10) bst.insert(5) bst.insert(15) bst.insert(2) bst.insert(7) print(bst.find(5)) # 输出 True print(bst.find(12)) # 输出 False # 中序遍历二叉搜索树 def inorder_traversal(node): if node: inorder_traversal(node.left) print(node.value) inorder_traversal(node.right) inorder_traversal(bst.root)
输出:
1 2 3 4 5 6 7 | True False 2 5 7 10 15 |
Java实现二叉搜索树
1. 树节点
public class TreeNode { private int value; private TreeNode left; private TreeNode right; TreeNode(int value) { this.value = value; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } public TreeNode getLeft() { return left; } public void setLeft(TreeNode left) { this.left = left; } public TreeNode getRight() { return right; } public void setRight(TreeNode right) { this.right = right; } }
2. 二叉搜索树
public class BinarySearchTree { private TreeNode root; public void insert(int value){ if(root == null){ root = new TreeNode(value); }else { insert(root,value); } } /** * 插入节点 * @param node * @param value */ private void insert(TreeNode node,int value){ // 插入值小于当前节点value,则插入在其左边树 if(value < node.getValue()){ if(node.getLeft() != null){ insert(node.getLeft() ,value); }else { node.setLeft(new TreeNode(value)); } }else { if(node.getRight() != null){ insert(node.getRight(),value); }else { node.setRight(new TreeNode(value)); } } } public boolean find(int value){ return find(this.root,value); } private boolean find(TreeNode node,int value){ if(node == null){ return false; } if(value == node.getValue()){ return true; }else if(value < node.getValue()){ return find(node.getLeft(),value); }else { return find(node.getRight(),value); } } }
测试:
public static void inOrderTraversal(TreeNode node){ if(node != null){ inOrderTraversal(node.getLeft()); System.out.println(node.getValue()); inOrderTraversal(node.getRight()); } } public static void main(String[] args) { BinarySearchTree binarySearchTree = new BinarySearchTree(); binarySearchTree.insert(10); binarySearchTree.insert(5); binarySearchTree.insert(15); binarySearchTree.insert(2); binarySearchTree.insert(7); System.out.println(binarySearchTree.find(5)); System.out.println(binarySearchTree.find(12)); inOrderTraversal(binarySearchTree.root); }
输出:
1 2 3 4 5 6 7 | true false 2 5 7 10 15 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)