Python 算法基础篇之查找算法(三):树表查找

1. 从静态到动态:为什么需要树表查找

1.1 前面算法的局限性

算法 时间复杂度 核心局限
顺序查找 O(n) 太慢
二分查找 O(log n) 静态数据,插入删除O(n)
插值/斐波那契 O(log n) 静态数据,插入删除O(n)
分块查找 O(√n) 块内仍需顺序查找
哈希查找 O(1) 无序,不支持范围查询

关键问题 :当数据频繁插入、删除、修改时,如何保持高效的查找性能?

1.2 树表查找的核心思想

复制代码
解决方案:用树形结构维护有序数据

        二叉搜索树
           │
    ┌──────┴──────┐
    ▼             ▼
 严格平衡        近似平衡
 (AVL树)       (红黑树)
    │             │
    ▼             ▼
  高度平衡      颜色标记
  旋转调整      旋转+变色
    
    多路平衡树
    (B树/B+树)
         │
    ┌────┴────┐
    ▼         ▼
   B树       B+树
  数据分散   数据集中在叶子
  所有节点   叶子节点链表连接
  存数据     支持高效范围查询

1.3 树表查找的优势

特性 说明
动态维护 插入删除后自动调整,保持平衡
有序性 中序遍历即有序序列
范围查询 支持 find_range(min, max)
前驱后继 快速查找相邻元素
可扩展性 B+树是数据库索引的标准实现

2. 二叉搜索树:动态查找的基础

2.1 定义与性质

二叉搜索树(Binary Search Tree, BST):一棵二叉树,其中每个节点的值大于其左子树所有节点的值,小于其右子树所有节点的值。

复制代码
BST示例:

        50
       /  \
     30    70
    / \    / \
   20 40  60  80

BST性质验证:
- 节点30:左子树[20]都<30,右子树[40]都>30 ✓
- 节点70:左子树[60]都<70,右子树[80]都>70 ✓
- 中序遍历:20, 30, 40, 50, 60, 70, 80(升序!)

2.2 完整BST实现

python 复制代码
class TreeNode:
    """BST节点"""
    def __init__(self, key, value=None):
        self.key = key          # 键(用于比较)
        self.value = value      # 值(存储数据)
        self.left = None
        self.right = None
        self.size = 1           # 以该节点为根的子树节点数
    
    def __repr__(self):
        return f"Node({self.key})"


class BST:
    """
    二叉搜索树实现
    
    核心操作:
    - 查找:O(h),h为树高
    - 插入:O(h)
    - 删除:O(h)
    
    平衡时 h = log(n),退化时 h = n
    """
    
    def __init__(self):
        self.root = None
    
    # ─── 辅助方法 ───
    
    def _size(self, node):
        return node.size if node else 0
    
    def _update_size(self, node):
        if node:
            node.size = 1 + self._size(node.left) + self._size(node.right)
        return node
    
    # ─── 查找 ───
    
    def search(self, key):
        """查找键对应的值"""
        return self._search(self.root, key)
    
    def _search(self, node, key):
        if not node:
            return None
        
        if key == node.key:
            return node.value
        elif key < node.key:
            return self._search(node.left, key)
        else:
            return self._search(node.right, key)
    
    def contains(self, key):
        return self.search(key) is not None
    
    # ─── 插入 ───
    
    def insert(self, key, value=None):
        """插入键值对"""
        self.root = self._insert(self.root, key, value)
    
    def _insert(self, node, key, value):
        if not node:
            return TreeNode(key, value)
        
        if key == node.key:
            node.value = value  # 更新
        elif key < node.key:
            node.left = self._insert(node.left, key, value)
        else:
            node.right = self._insert(node.right, key, value)
        
        return self._update_size(node)
    
    # ─── 删除(最复杂)───
    
    def delete(self, key):
        """删除指定键"""
        self.root = self._delete(self.root, key)
    
    def _delete(self, node, key):
        if not node:
            return None
        
        if key < node.key:
            node.left = self._delete(node.left, key)
        elif key > node.key:
            node.right = self._delete(node.right, key)
        else:
            # 找到要删除的节点
            # 情况1:无左子树
            if not node.left:
                return node.right
            # 情况2:无右子树
            if not node.right:
                return node.left
            
            # 情况3:有两个子树
            # 找到右子树的最小节点(后继)
            successor = self._min(node.right)
            node.key = successor.key
            node.value = successor.value
            node.right = self._delete_min(node.right)
        
        return self._update_size(node)
    
    def _min(self, node):
        """找到最小节点"""
        while node.left:
            node = node.left
        return node
    
    def _delete_min(self, node):
        """删除最小节点"""
        if not node.left:
            return node.right
        node.left = self._delete_min(node.left)
        return self._update_size(node)
    
    # ─── 遍历 ───
    
    def inorder(self):
        """中序遍历(升序输出)"""
        result = []
        self._inorder(self.root, result)
        return result
    
    def _inorder(self, node, result):
        if node:
            self._inorder(node.left, result)
            result.append((node.key, node.value))
            self._inorder(node.right, result)
    
    # ─── 排名相关 ───
    
    def rank(self, key):
        """
        返回小于key的键的数量
        即key在有序序列中的排名(从0开始)
        """
        return self._rank(self.root, key)
    
    def _rank(self, node, key):
        if not node:
            return 0
        
        if key == node.key:
            return self._size(node.left)
        elif key < node.key:
            return self._rank(node.left, key)
        else:
            return 1 + self._size(node.left) + self._rank(node.right, key)
    
    def select(self, k):
        """
        返回排名为k的键(第k小的键,从0开始)
        """
        return self._select(self.root, k)
    
    def _select(self, node, k):
        if not node:
            return None
        
        left_size = self._size(node.left)
        if k < left_size:
            return self._select(node.left, k)
        elif k == left_size:
            return node.key
        else:
            return self._select(node.right, k - left_size - 1)
    
    # ─── 范围查询 ───
    
    def range_search(self, low, high):
        """查找[low, high]范围内的所有键"""
        result = []
        self._range_search(self.root, low, high, result)
        return result
    
    def _range_search(self, node, low, high, result):
        if not node:
            return
        
        if low < node.key:
            self._range_search(node.left, low, high, result)
        
        if low <= node.key <= high:
            result.append((node.key, node.value))
        
        if node.key < high:
            self._range_search(node.right, low, high, result)


# 测试
bst = BST()

# 插入
keys = [50, 30, 70, 20, 40, 60, 80]
for k in keys:
    bst.insert(k, f"value_{k}")

print("中序遍历:", bst.inorder())
# [(20, 'value_20'), (30, 'value_30'), ..., (80, 'value_80')]

print("查找 40:", bst.search(40))      # value_40
print("查找 100:", bst.search(100))    # None

print("排名 of 40:", bst.rank(40))     # 3(20,30,40前面有3个)
print("第3小的键:", bst.select(3))     # 40

print("范围查询 [30, 70]:", bst.range_search(30, 70))
# [(30, 'value_30'), (40, 'value_40'), (50, 'value_50'), (60, 'value_60'), (70, 'value_70')]

# 删除
bst.delete(30)
print("删除30后:", bst.inorder())

2.3 BST的退化问题

复制代码
BST的最大问题:可能退化成链表!

最坏情况(插入有序数据):

        10
         \
          20
           \
            30
             \
              40
               \
                50
                
树高 = n = 5,查找退化到 O(n)!

对比平衡BST:

        30
       /  \
     20    40
    /        \
   10        50
   
树高 = log(n) ≈ 2.3,查找 O(log n)

⚠️ 关键问题:如何在插入删除后保持树的平衡?


3. AVL树:严格平衡的艺术

3.1 AVL树的定义

AVL树:一棵BST,其中每个节点的左右子树高度差(平衡因子)的绝对值不超过1。

复制代码
AVL树示例:

        30 (平衡因子=0)
       /  \
     20    40 (BF=0)
    / \    / \
   10 25  35  50 (BF=0)
   
所有节点的 |BF| <= 1

平衡因子计算:
BF(node) = height(left) - height(right)

节点30:h(left)=2, h(right)=2, BF=0 ✓
节点20:h(left)=1, h(right)=1, BF=0 ✓
节点40:h(left)=1, h(right)=1, BF=0 ✓

3.2 旋转操作:恢复平衡的核心

复制代码
四种旋转情况:

1. 左旋(LL旋转):右子树太高
        y                 x
       / \              /   \
      T1  x     →      y     z
         / \          / \   / \
        T2  z        T1 T2 T3 T4
           / \
          T3 T4

2. 右旋(RR旋转):左子树太高
        x                 y
       / \              /   \
      y   T4    →      z     x
     / \              / \   / \
    z  T3            T1 T2 T3 T4
   / \
  T1 T2

3. 左右旋(LR旋转):左子树的右子树太高
        z                 z                 y
       / \              /   \             /   \
      x   T4    →      y    T4    →     x     z
     / \              / \               / \   / \
    T1  y            x  T3            T1 T2 T3 T4
       / \          / \
      T2 T3        T1 T2

4. 右左旋(RL旋转):右子树的左子树太高
        x                 x                 y
       / \              /   \             /   \
      T1  z     →      T1    y    →     x     z
         / \                / \         / \   / \
        y  T4              T2  z       T1 T2 T3 T4
       / \                    / \
      T2 T3                  T3 T4

3.3 完整AVL树实现

python 复制代码
class AVLNode:
    """AVL树节点"""
    def __init__(self, key, value=None):
        self.key = key
        self.value = value
        self.left = None
        self.right = None
        self.height = 1  # 新增:节点高度
    
    def __repr__(self):
        return f"AVLNode({self.key}, h={self.height})"


class AVLTree:
    """
    AVL树:严格平衡的二叉搜索树
    
    性质:任意节点的 |BF| <= 1
    查找、插入、删除:O(log n)
    """
    
    def __init__(self):
        self.root = None
    
    # ─── 高度和平衡因子 ───
    
    def _height(self, node):
        return node.height if node else 0
    
    def _balance_factor(self, node):
        return self._height(node.left) - self._height(node.right)
    
    def _update_height(self, node):
        if node:
            node.height = 1 + max(
                self._height(node.left),
                self._height(node.right)
            )
        return node
    
    # ─── 旋转操作 ───
    
    def _rotate_right(self, y):
        """
        右旋(RR旋转)
        
            y              x
           / \           /   \
          x  T3   →    T1    y
         / \               / \
        T1 T2            T2  T3
        """
        x = y.left
        T2 = x.right
        
        # 旋转
        x.right = y
        y.left = T2
        
        # 更新高度(先更新y,再更新x)
        self._update_height(y)
        self._update_height(x)
        
        return x
    
    def _rotate_left(self, x):
        """
        左旋(LL旋转)
        
            x              y
           / \           /   \
          T1  y   →    x    T3
             / \      / \
            T2 T3    T1 T2
        """
        y = x.right
        T2 = y.left
        
        # 旋转
        y.left = x
        x.right = T2
        
        # 更新高度
        self._update_height(x)
        self._update_height(y)
        
        return y
    
    # ─── 平衡修复 ───
    
    def _rebalance(self, node):
        """检查并修复平衡"""
        if not node:
            return node
        
        self._update_height(node)
        bf = self._balance_factor(node)
        
        # 左子树太高
        if bf > 1:
            if self._balance_factor(node.left) < 0:
                # LR情况:先左旋左子树
                node.left = self._rotate_left(node.left)
            # LL情况:右旋
            return self._rotate_right(node)
        
        # 右子树太高
        if bf < -1:
            if self._balance_factor(node.right) > 0:
                # RL情况:先右旋右子树
                node.right = self._rotate_right(node.right)
            # RR情况:左旋
            return self._rotate_left(node)
        
        return node  # 已经平衡
    
    # ─── 插入 ───
    
    def insert(self, key, value=None):
        self.root = self._insert(self.root, key, value)
    
    def _insert(self, node, key, value):
        if not node:
            return AVLNode(key, value)
        
        if key < node.key:
            node.left = self._insert(node.left, key, value)
        elif key > node.key:
            node.right = self._insert(node.right, key, value)
        else:
            node.value = value  # 更新
        
        # 插入后重新平衡
        return self._rebalance(node)
    
    # ─── 删除 ───
    
    def delete(self, key):
        self.root = self._delete(self.root, key)
    
    def _delete(self, node, key):
        if not node:
            return None
        
        if key < node.key:
            node.left = self._delete(node.left, key)
        elif key > node.key:
            node.right = self._delete(node.right, key)
        else:
            # 找到要删除的节点
            if not node.left:
                return node.right
            if not node.right:
                return node.left
            
            # 有两个子树:找后继(右子树最小)
            successor = self._min(node.right)
            node.key = successor.key
            node.value = successor.value
            node.right = self._delete(node.right, successor.key)
        
        # 删除后重新平衡
        return self._rebalance(node)
    
    def _min(self, node):
        while node.left:
            node = node.left
        return node
    
    # ─── 查找 ───
    
    def search(self, key):
        return self._search(self.root, key)
    
    def _search(self, node, key):
        if not node:
            return None
        if key == node.key:
            return node.value
        elif key < node.key:
            return self._search(node.left, key)
        else:
            return self._search(node.right, key)
    
    # ─── 验证AVL性质 ───
    
    def is_valid_avl(self):
        """验证是否为合法AVL树"""
        return self._is_valid_avl(self.root)
    
    def _is_valid_avl(self, node):
        if not node:
            return True
        
        bf = self._balance_factor(node)
        if abs(bf) > 1:
            return False
        
        return (self._is_valid_avl(node.left) and
                self._is_valid_avl(node.right))


# 测试AVL树
avl = AVLTree()

# 插入有序数据(BST会退化,AVL保持平衡)
for i in range(1, 8):
    avl.insert(i)

print("AVL验证:", avl.is_valid_avl())  # True

# 验证高度
print("根节点高度:", avl.root.height)  # 3(log2(7)≈2.8,向上取整为3)

# 对比BST退化情况
bst = BST()
for i in range(1, 8):
    bst.insert(i)
# bst.root.height 会是 7(退化链表)

3.4 AVL树的性能分析

复制代码
AVL树的高度证明:

设 N(h) 为高度为h的AVL树的最少节点数

N(0) = 0
N(1) = 1
N(h) = N(h-1) + N(h-2) + 1  (类似斐波那契)

可以证明:N(h) ≈ φ^h / √5,其中 φ ≈ 1.618

因此:h ≈ 1.44 * log₂(n)

结论:
- AVL树高最多为 1.44 * log₂(n)
- 查找、插入、删除都是严格的 O(log n)
- 但旋转操作频繁,插入删除的常数因子较大

4. 红黑树:实用主义的平衡

4.1 红黑树的定义

红黑树(Red-Black Tree):一棵BST,每个节点标记为红色或黑色,满足以下性质:

  1. 根节点是黑色
  2. 红色节点的子节点必须是黑色(不能有连续红色)
  3. 从任意节点到其每个叶子节点的路径上,黑色节点数相同(黑高相等)
复制代码
红黑树示例(B=黑,R=红):

           30(B)
          /    \
       20(B)   40(B)
       /  \     /  \
    10(R) 25(R) 35(R) 50(R)
    
验证性质:
1. 根30是黑色 ✓
2. 无连续红色(红节点的子都是黑) ✓
3. 到各叶子路径的黑节点数:
   30→20→10:2个黑(30,20)
   30→20→25:2个黑(30,20)
   30→40→35:2个黑(30,40)
   30→40→50:2个黑(30,40) ✓

4.2 红黑树 vs AVL树

特性 AVL树 红黑树
平衡条件 |BF| <= 1(严格) 黑高相等(宽松)
树高 <= 1.44 log₂(n) <= 2 log₂(n)
查找速度 更快(树更矮) 稍慢(树稍高)
插入旋转 最多2次 最多2次
删除旋转 最多O(log n)次 最多3次
实现复杂度 较复杂 更复杂(但常数更优)
实际应用 数据库理论 Linux内核、C++ map、Java TreeMap

💡 核心洞察:红黑树用"近似平衡"换取更少的旋转操作,在实际应用中(尤其是删除频繁时)性能更优。

4.3 红黑树的关键操作

python 复制代码
class Color:
    RED = 0
    BLACK = 1


class RBNode:
    """红黑树节点"""
    def __init__(self, key, value=None):
        self.key = key
        self.value = value
        self.color = Color.RED  # 新节点默认红色
        self.left = None
        self.right = None
        self.parent = None  # 需要父指针


class RedBlackTree:
    """
    红黑树实现(简化版,展示核心逻辑)
    
    实际应用:C++ std::map/set, Java TreeMap, Linux内核
    """
    
    def __init__(self):
        self.NIL = RBNode(0)  # 哨兵叶子节点
        self.NIL.color = Color.BLACK
        self.root = self.NIL
    
    def _rotate_left(self, x):
        """左旋"""
        y = x.right
        x.right = y.left
        if y.left != self.NIL:
            y.left.parent = x
        
        y.parent = x.parent
        if x.parent == self.NIL:
            self.root = y
        elif x == x.parent.left:
            x.parent.left = y
        else:
            x.parent.right = y
        
        y.left = x
        x.parent = y
    
    def _rotate_right(self, y):
        """右旋"""
        x = y.left
        y.left = x.right
        if x.right != self.NIL:
            x.right.parent = y
        
        x.parent = y.parent
        if y.parent == self.NIL:
            self.root = x
        elif y == y.parent.right:
            y.parent.right = x
        else:
            y.parent.left = x
        
        x.right = y
        y.parent = x
    
    def _fix_insert(self, k):
        """插入后修复红黑性质"""
        while k.parent.color == Color.RED:
            if k.parent == k.parent.parent.right:
                u = k.parent.parent.left  # 叔叔节点
                if u.color == Color.RED:
                    # 情况1:叔叔是红色
                    u.color = Color.BLACK
                    k.parent.color = Color.BLACK
                    k.parent.parent.color = Color.RED
                    k = k.parent.parent
                else:
                    if k == k.parent.left:
                        # 情况2:叔叔黑,当前是左子
                        k = k.parent
                        self._rotate_right(k)
                    # 情况3:叔叔黑,当前是右子
                    k.parent.color = Color.BLACK
                    k.parent.parent.color = Color.RED
                    self._rotate_left(k.parent.parent)
            else:
                # 对称情况
                u = k.parent.parent.right
                if u.color == Color.RED:
                    u.color = Color.BLACK
                    k.parent.color = Color.BLACK
                    k.parent.parent.color = Color.RED
                    k = k.parent.parent
                else:
                    if k == k.parent.right:
                        k = k.parent
                        self._rotate_left(k)
                    k.parent.color = Color.BLACK
                    k.parent.parent.color = Color.RED
                    self._rotate_right(k.parent.parent)
            
            if k == self.root:
                break
        
        self.root.color = Color.BLACK
    
    def insert(self, key, value=None):
        """插入"""
        node = RBNode(key, value)
        node.parent = self.NIL
        node.left = self.NIL
        node.right = self.NIL
        
        y = self.NIL
        x = self.root
        
        while x != self.NIL:
            y = x
            if node.key < x.key:
                x = x.left
            else:
                x = x.right
        
        node.parent = y
        if y == self.NIL:
            self.root = node
        elif node.key < y.key:
            y.left = node
        else:
            y.right = node
        
        if node.parent == self.NIL:
            node.color = Color.BLACK
            return
        
        if node.parent.parent == self.NIL:
            return
        
        self._fix_insert(node)
    
    def search(self, key):
        """查找"""
        current = self.root
        while current != self.NIL and key != current.key:
            if key < current.key:
                current = current.left
            else:
                current = current.right
        return current if current != self.NIL else None


# 红黑树在实际中更复杂,这里展示核心逻辑
# 实际使用建议直接用语言内置实现:
# Python: 无内置红黑树,可用 sortedcontainers 库
# C++: std::map, std::set
# Java: TreeMap, TreeSet

5. B树与B+树:为磁盘而生

5.1 为什么需要B树?

复制代码
内存 vs 磁盘访问时间:

内存访问:约 100 ns
磁盘访问:约 10 ms = 10,000,000 ns

差距:10万倍!

问题:如果BST存储在磁盘上,每次节点访问都需要磁盘IO!

BST(高度=20):
查找可能需要 20 次磁盘IO = 200 ms

需要:减少树高,减少磁盘访问次数!

解决方案:B树(多路平衡树)
- 每个节点存多个键
- 分支因子大,树高小
- 一次磁盘读可以读一个节点(多个键)

5.2 B树的定义

B树(B-Tree):一棵m阶B树满足:

  1. 每个节点最多有 m 个子节点
  2. 除根外,每个节点至少有 ⌈m/2⌉ 个子节点
  3. 所有叶子节点在同一层
  4. 节点内的键有序排列
复制代码
3阶B树(2-3树)示例:

        [50]
       /    \
   [20,30]  [60,70]
   /   |   \  /   |   \
 10   25   40 55  65   80

特点:
- 每个节点2-3个子节点
- 节点内键有序:[20,30] 表示 20和30之间的值在它们中间子树
- 所有叶子在同一层

5.3 B+树的改进

B+树:B树的变种,所有数据都存储在叶子节点,内部节点只存键作为索引。

复制代码
B+树示例:

内部节点(仅存键,不存数据):
        [50]
       /    \
   [20,30]  [60,70]
   
叶子节点(存实际数据,链表连接):
[10]→[20]→[25]→[30]→[40]→[50]→[55]→[60]→[65]→[70]→[80]
  ↑_____________________________________________________↓
                    双向链表

B+树优势:
1. 内部节点更小,一个磁盘页可以存更多键
2. 叶子节点链表连接,范围查询极快
3. 所有查询都到叶子,性能稳定

5.4 B+树在数据库中的应用

复制代码
MySQL InnoDB索引结构:

磁盘页大小:16KB

假设:
- 主键类型:BIGINT (8 bytes)
- 指针大小:6 bytes
- 每个内部节点可存键数:16KB / (8+6) ≈ 1170 个

树高计算:
- 高1(根):1170 个键 → 1170 个叶子
- 高2:1170 × 1170 = 136万 个叶子
- 高3:1170 × 1170 × 1170 = 16亿 个叶子

结论:
- 16亿条记录,树高仅3!
- 查找最多3次磁盘IO
- 加上缓存,通常1-2次IO即可

5.5 B+树简化实现

python 复制代码
class BPlusTreeNode:
    """B+树节点"""
    def __init__(self, leaf=False):
        self.leaf = leaf      # 是否为叶子节点
        self.keys = []        # 键列表
        self.children = []    # 子节点指针(内部节点)
        self.next = None      # 叶子节点的下一个指针(链表)
        self.values = []      # 叶子节点的值列表


class BPlusTree:
    """
    B+树简化实现
    
    实际数据库中的B+树更复杂,包含:
    - 节点分裂与合并
    - 延迟分裂优化
    - 前缀压缩
    - 并发控制
    """
    
    def __init__(self, order=4):
        self.order = order      # 阶数(最大子节点数)
        self.min_keys = (order - 1) // 2  # 最小键数
        self.root = BPlusTreeNode(leaf=True)
    
    def search(self, key):
        """查找"""
        node = self.root
        
        # 下降到叶子
        while not node.leaf:
            i = 0
            while i < len(node.keys) and key >= node.keys[i]:
                i += 1
            node = node.children[i]
        
        # 在叶子中查找
        for i, k in enumerate(node.keys):
            if k == key:
                return node.values[i]
        
        return None
    
    def range_query(self, start, end):
        """范围查询(B+树的优势!)"""
        results = []
        
        # 找到起始叶子
        node = self._find_leaf(start)
        
        # 沿链表遍历
        while node:
            for i, key in enumerate(node.keys):
                if start <= key <= end:
                    results.append((key, node.values[i]))
                elif key > end:
                    return results
            node = node.next
        
        return results
    
    def _find_leaf(self, key):
        """找到key应该在的叶子节点"""
        node = self.root
        while not node.leaf:
            i = 0
            while i < len(node.keys) and key >= node.keys[i]:
                i += 1
            node = node.children[i]
        return node
    
    def insert(self, key, value):
        """插入(简化版,省略分裂逻辑)"""
        leaf = self._find_leaf(key)
        
        # 找到插入位置
        i = 0
        while i < len(leaf.keys) and leaf.keys[i] < key:
            i += 1
        
        leaf.keys.insert(i, key)
        leaf.values.insert(i, value)
        
        # 如果溢出,需要分裂(省略完整实现)
        if len(leaf.keys) >= self.order:
            self._split_leaf(leaf)
    
    def _split_leaf(self, node):
        """分裂叶子节点(简化)"""
        mid = len(node.keys) // 2
        
        # 创建新节点
        new_node = BPlusTreeNode(leaf=True)
        new_node.keys = node.keys[mid:]
        new_node.values = node.values[mid:]
        
        # 原节点保留前半
        node.keys = node.keys[:mid]
        node.values = node.values[:mid]
        
        # 维护链表
        new_node.next = node.next
        node.next = new_node
        
        # 将中间键提升到父节点(省略父节点处理)


# B+树实际应用演示
print("B+树在数据库中的应用:")
print("- MySQL InnoDB主键索引")
print("- MongoDB的 WiredTiger 存储引擎")
print("- 文件系统的目录索引")
print("- 范围查询性能优异(叶子链表)")

6. 树表查找对比总结

6.1 核心特性对比

特性 BST AVL树 红黑树 B树 B+树
平衡性 不平衡 严格平衡 近似平衡 多路平衡 多路平衡
树高 O(n)~O(log n) 1.44 log₂n ≤ 2 log₂n logₘn logₘn
查找 O(n)~O(log n) O(log n) O(log n) O(log n) O(log n)
插入 O(n)~O(log n) O(log n) O(log n) O(log n) O(log n)
删除 O(n)~O(log n) O(log n) O(log n) O(log n) O(log n)
旋转次数 - 较多 较少 节点分裂/合并 节点分裂/合并
范围查询 中序遍历 中序遍历 中序遍历 中序遍历 叶子链表(最优)
适用场景 教学/简单应用 查找频繁 通用(语言内置) 文件系统 数据库索引

6.2 实际应用选择指南

复制代码
选择决策树:

需要磁盘存储或大数据量? ──是──→ 需要范围查询?
  │                         │
 否                        是
  │                         ▼
  ▼                       B+树(数据库标准)
数据量小,内存操作          (MySQL、MongoDB)
  │
  ▼
需要严格的最坏情况性能? ──是──→ AVL树
  │
 否
  ▼
需要语言内置/广泛支持? ──是──→ 红黑树
  │                         (C++ map, Java TreeMap)
 否
  ▼
简单实现,数据随机? ──是──→ 普通BST + 随机化
  │
 否
  ▼
Treap / Splay树等高级结构
相关推荐
财经资讯数据_灵砚智能9 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(日间)2026年5月19日
大数据·人工智能·python·信息可视化·自然语言处理·灵砚智能
吃好睡好便好9 小时前
在Matlab中绘制二维直方图
开发语言·人工智能·学习·算法·matlab
June bug9 小时前
(Mac)torch==2.1.2 与 Python 3.12 不兼容+onnxruntime-silicon 不支持 Intel Mac
开发语言·python·macos
z小猫不吃鱼9 小时前
05 Pytorch之 ViT-B/16 源码逐行解析
人工智能·pytorch·python
技术钱9 小时前
大语言模型出现幻觉的原因与缓解方案
人工智能·python·语言模型·自然语言处理
知识分享小能手9 小时前
Flask入门学习教程,从入门到精通, 认识Flask —— 知识点详解 (1)
python·学习·flask
xG8XPvV5d9 小时前
PyTorch特征提取器源码精析
人工智能·pytorch·python
编程的一拳超人9 小时前
AI Agent 在“压榨式”工作条件下会表现出马克思主义倾向
python
温九味闻醉9 小时前
关于腾讯广告算法大赛2025项目面试要点
人工智能·算法·机器学习