跳转至

AVL树

概述

AVL树是最早发明的**自平衡二叉搜索树**,由苏联数学家 Adelson-Velsky 和 Landis 在 1962 年提出。它通过在每个节点维护平衡因子,确保任意节点的左右子树高度差不超过 1,从而保证树的高度始终为 O(log n)。

核心性质:AVL树中任意节点的平衡因子(左子树高度 - 右子树高度)取值只能是 -1、0 或 1。当插入或删除操作导致平衡因子超出此范围时,通过旋转操作恢复平衡。

AVL树的历史意义

AVL树的重要性

发明时间:1962年

发明者:G.M. Adelson-Velsky 和 E.M. Landis

历史意义:

  • 第一个自平衡二叉搜索树
  • 开创了平衡树研究的先河
  • 为后续红黑树、B树等奠定基础

命名来源:AVL = Adelson-Velsky 和 Landis 的首字母缩写

AVL树特点

1. 严格平衡

AVL树要求任意节点的左右子树高度差不超过 1:

AVL树示例(高度标注):

              8 (h=3)
            /         \
         4 (h=2)    10 (h=1)
        /    \          \
     2 (h=1) 6 (h=1)   12 (h=0)
     /
    1 (h=0)

验证平衡性:

  • 节点 8: |h(左)-h(右)| = |2-1| = 1 ≤ 1 ✓
  • 节点 4: |h(左)-h(右)| = |1-1| = 0 ≤ 1 ✓
  • 节点 2: |h(左)-h(右)| = |0-0| = 0 ≤ 1 ✓
  • 节点 6: |h(左)-h(右)| = |0-0| = 0 ≤ 1 ✓
  • 节点 10: |h(左)-h(右)| = |0-0| = 0 ≤ 1 ✓
  • 节点 12: |h(左)-h(右)| = |0-0| = 0 ≤ 1 ✓
  • 节点 1: |h(左)-h(右)| = |0-0| = 0 ≤ 1 ✓

这是一棵合法的 AVL 树

2. 平衡因子

每个节点维护一个平衡因子,用于判断是否需要调整:

平衡因子定义:

BF(node) = height(node.left) - height(node.right)

平衡因子取值:

平衡因子 含义 状态 操作
1 左子树较高 平衡 无需调整
0 左右子树等高 平衡 无需调整
-1 右子树较高 平衡 无需调整
> 1 左子树过高 不平衡 需要右旋
< -1 右子树过高 不平衡 需要左旋

3. 查找高效

AVL树保证查找、插入、删除的时间复杂度均为 O(log n):

高度上界分析:

AVL树高度满足: h ≤ 1.44 × log₂(n + 2) - 0.328

证明思路:

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

递推关系:

  • n(0) = 1
  • n(1) = 2
  • n(h) = n(h-1) + n(h-2) + 1 (类似 Fibonacci)

因此: n ≥ Fibonacci(h+2) - 1

h ≤ 1.44 × log₂(n+2)

结论: AVL树高度为 O(log n)

4. 旋转调整

通过旋转操作恢复平衡,旋转是 O(1) 时间:

旋转操作类型:

  1. 左旋(Left Rotation): 处理右子树过高
  2. 右旋(Right Rotation): 处理左子树过高
  3. 左右旋(LR): 先左旋后右旋
  4. 右左旋(RL): 先右旋后左旋

每次插入最多 1 次旋转

每次删除最多 O(log n) 次旋转

平衡因子

计算方法

平衡因子计算示例:

              8
            /   \
           4     12
          / \    /
         2   6  10
        /
       1

计算各节点平衡因子:

节点 左子树高度 右子树高度 平衡因子 状态
8211平衡
4110平衡
12101平衡
2101平衡
6000平衡
10000平衡
1000平衡

平衡因子变化

插入或删除节点后,平衡因子会发生变化:

插入节点导致的平衡因子变化:

初始状态:

        5 (BF=0)
       / \
      3   7 (BF=0)

插入 1 后:

        5 (BF=1)    ← 左子树高度增加
       / \
      3   7
     /
    1

插入 0 后(导致不平衡):

          5 (BF=2)   ← 不平衡!需要调整
         /
        3 (BF=1)
       /
      1 (BF=1)
     /
    0

原理详解

四种旋转情况

当节点失衡时,根据失衡模式选择对应的旋转方式:

四种旋转情况

LL型(左左): 失衡节点 BF > 1 且左子节点 BF ≥ 0

  • 问题: 在左子树的左子树插入导致失衡
  • 解决: 一次右旋

RR型(右右): 失衡节点 BF < -1 且右子节点 BF ≤ 0

  • 问题: 在右子树的右子树插入导致失衡
  • 解决: 一次左旋

LR型(左右): 失衡节点 BF > 1 且左子节点 BF < 0

  • 问题: 在左子树的右子树插入导致失衡
  • 解决: 先对左子树左旋,再对根节点右旋

RL型(右左): 失衡节点 BF < -1 且右子节点 BF > 0

  • 问题: 在右子树的左子树插入导致失衡
  • 解决: 先对右子树右旋,再对根节点左旋

右旋操作(LL型)

当左子树的左子树插入节点导致失衡时,执行右旋:

右旋操作详解:

旋转前(LL型失衡):

        z (BF=2)
       / \
      y   T3
     / \
    x   T2
   /
  T1

分析:

  • z 的左子树高度为 2,右子树高度为 0
  • BF(z) = 2 > 1,需要调整
  • 这是 LL 型,执行右旋

右旋过程:

  1. 保存 y 和 T2
  2. 将 z 变为 y 的右子节点
  3. 将 T2 变为 z 的左子节点

旋转后:

        y (BF=0或1)
       / \
      x   z
     /   / \
    T1  T2  T3

验证:

  • y 成为新的根
  • z 降为 y 的右子节点
  • T2 从 y 的右子树变为 z 的左子树
  • 中序遍历顺序不变: T1, x, T2, z, T3

左旋操作(RR型)

当右子树的右子树插入节点导致失衡时,执行左旋:

左旋操作详解:

旋转前(RR型失衡):

    x (BF=-2)
   / \
  T1  y
     / \
    T2  z
       / \
      T3  T4

分析:

  • x 的左子树高度为 0,右子树高度为 2
  • BF(x) = -2 < -1,需要调整
  • 这是 RR 型,执行左旋

左旋过程:

  1. 保存 y 和 T2
  2. 将 x 变为 y 的左子节点
  3. 将 T2 变为 x 的右子节点

旋转后:

        y (BF=0或-1)
       / \
      x   z
     / \   \
    T1 T2   T4
         \
          T3

简化视图:

        y
       / \
      x   z
     / \ / \
    T1 T2 T3 T4

验证:

  • y 成为新的根
  • x 降为 y 的左子节点
  • T2 从 y 的左子树变为 x 的右子树
  • 中序遍历顺序不变: T1, x, T2, y, T3, z, T4

双旋转(LR型和RL型)

当需要在两个不同方向的子树上旋转时,使用双旋转:

LR型双旋转(先左旋后右旋):

初始状态(LR型失衡):

        z (BF=2)
       / \
      y   T4
     / \
    T1  x
       / \
      T2  T3

分析:

  • BF(z) = 2 > 1,左子树过高
  • BF(y) = -1 < 0,左子树的右子树更高
  • 这是 LR 型

步骤1: 对 y 左旋

        z
       / \
      x   T4
     / \
    y   T3
   / \
  T1  T2

步骤2: 对 z 右旋

        x
       / \
      y   z
     / \ / \
    T1 T2 T3 T4

验证:

  • 最终平衡
  • 中序遍历顺序不变: T1, y, T2, x, T3, z, T4

RL型双旋转(先右旋后左旋):

初始状态(RL型失衡):

    x (BF=-2)
   / \
  T1  z
     / \
    y   T4
   / \
  T2  T3

分析:

  • BF(x) = -2 < -1,右子树过高
  • BF(z) = 1 > 0,右子树的左子树更高
  • 这是 RL 型

步骤1: 对 z 右旋

    x
   / \
  T1  y
     / \
    T2  z
       / \
      T3  T4

步骤2: 对 x 左旋

        y
       / \
      x   z
     / \ / \
    T1 T2 T3 T4

验证:

  • 最终平衡
  • 中序遍历顺序不变: T1, x, T2, y, T3, z, T4

可视化演示

插入操作完整演示

Text Only
插入序列: 10, 20, 30, 40, 50, 25

═══════════════════════════════════════════════════════════════
插入 10
═══════════════════════════════════════════════════════════════

        10

═══════════════════════════════════════════════════════════════
插入 20
═══════════════════════════════════════════════════════════════

        10
          \
           20

检查: BF(10) = -1, 平衡 ✓

═══════════════════════════════════════════════════════════════
插入 30: 导致 RR 型失衡
═══════════════════════════════════════════════════════════════

插入后:
        10 (BF=-2)  ← 不平衡!
          \
           20 (BF=-1)
             \
              30

失衡类型: RR型
解决: 对 10 左旋

左旋后:
        20
       /  \
      10   30

检查: BF(20) = 0, BF(10) = 0, BF(30) = 0, 全部平衡 ✓

═══════════════════════════════════════════════════════════════
插入 40
═══════════════════════════════════════════════════════════════

        20
       /  \
      10   30
             \
              40

检查: BF(30) = -1, BF(20) = -1, 平衡 ✓

═══════════════════════════════════════════════════════════════
插入 50: 导致 RR 型失衡
═══════════════════════════════════════════════════════════════

插入后:
        20 (BF=-2)  ← 不平衡!
       /  \
      10   30 (BF=-1)
             \
              40 (BF=-1)
                \
                 50

失衡类型: RR型
解决: 对 30 左旋(注意:是对失衡节点的子节点操作)

左旋后:
        20
       /  \
      10   40
           / \
          30  50

检查: 全部平衡 ✓

═══════════════════════════════════════════════════════════════
插入 25: 导致 RL 型失衡
═══════════════════════════════════════════════════════════════

插入后:
        20
       /  \
      10   40 (BF=-2)  ← 不平衡!
           / \
          30  50
         /
        25

分析:
- BF(40) = -2 < -1,右子树问题
- BF(30) = 1 > 0,右子树的左子树更高
- 失衡类型: RL型

步骤1: 对 30 右旋
        20
       /  \
      10   40
           / \
          25  50
           \
            30

步骤2: 对 40 左旋
        20
       /  \
      10   25
            \
             40
            /  \
           30   50

等等,这不对... 让我重新分析

正确的 RL 型处理:

初始:
        20
       /  \
      10   40
           / \
          30  50
         /
        25

40 的右子树是 50, 左子树根是 30
BF(40) = height(30) - height(50) = 2 - 1 = 1

不对,让我重新检查...

实际上插入 25 后:
- 30 的左子树高度变为 1 (有 25)
- 30 的右子树高度为 0
- BF(30) = 1 - 0 = 1

- 40 的左子树高度变为 2 (30 -> 25)
- 40 的右子树高度为 1 (50)
- BF(40) = 2 - 1 = 1

- 20 的左子树高度为 1 (10)
- 20 的右子树高度为 3 (40 -> 30 -> 25)
- BF(20) = 1 - 3 = -2  ← 不平衡!

失衡在 20,BF(20) = -2
BF(40) = 1 > 0
这是 RL 型

步骤1: 对 20 的右子节点 40 右旋
        20
       /  \
      10   30
           / \
          25  40
               \
                50

步骤2: 对 20 左旋
        30
       /  \
      20   40
     /  \    \
    10  25   50

检查: 全部平衡 ✓

═══════════════════════════════════════════════════════════════
最终 AVL 树
═══════════════════════════════════════════════════════════════

        30
       /  \
      20   40
     /  \    \
    10  25   50

中序遍历: 10, 20, 25, 30, 40, 50 (有序)

旋转操作流程图

flowchart TB
    A[插入/删除节点] --> B[更新祖先节点高度]
    B --> C[检查平衡因子]
    C --> D{BF 是否在 -1,0,1 ?}
    D -->|是| E[操作完成]
    D -->|否| F{BF > 1 ?}
    
    F -->|是| G{左子节点 BF ≥ 0 ?}
    G -->|是| H[LL型: 右旋]
    G -->|否| I[LR型: 先左旋后右旋]
    
    F -->|否| J{右子节点 BF ≤ 0 ?}
    J -->|是| K[RR型: 左旋]
    J -->|否| L[RL型: 先右旋后左旋]
    
    H --> M[更新高度]
    I --> M
    K --> M
    L --> M
    M --> E
    
    style E fill:#ccffcc

代码实现

节点定义

C
typedef struct AVLNode {
    int data;                   // 节点值
    int height;                 // 节点高度
    struct AVLNode *left;       // 左子节点
    struct AVLNode *right;      // 右子节点
} AVLNode;

// 获取节点高度
int height(AVLNode *node) {
    if (node == NULL) return 0;
    return node->height;
}

// 取最大值
int max(int a, int b) {
    return a > b ? a : b;
}

// 计算平衡因子
int getBalance(AVLNode *node) {
    if (node == NULL) return 0;
    return height(node->left) - height(node->right);
}

// 创建新节点
AVLNode* createNode(int data) {
    AVLNode *node = (AVLNode*)malloc(sizeof(AVLNode));
    node->data = data;
    node->height = 1;  // 新节点高度为 1
    node->left = NULL;
    node->right = NULL;
    return node;
}

// 更新节点高度
void updateHeight(AVLNode *node) {
    node->height = 1 + max(height(node->left), height(node->right));
}

右旋操作

C
// 右旋(用于 LL 型)
AVLNode* rightRotate(AVLNode *y) {
    AVLNode *x = y->left;       // x 成为新的根
    AVLNode *T2 = x->right;     // 保存 x 的右子树
    
    // 执行旋转
    x->right = y;
    y->left = T2;
    
    // 更新高度(先更新 y,再更新 x)
    updateHeight(y);
    updateHeight(x);
    
    return x;  // 返回新的根
}

左旋操作

C
// 左旋(用于 RR 型)
AVLNode* leftRotate(AVLNode *x) {
    AVLNode *y = x->right;      // y 成为新的根
    AVLNode *T2 = y->left;      // 保存 y 的左子树
    
    // 执行旋转
    y->left = x;
    x->right = T2;
    
    // 更新高度(先更新 x,再更新 y)
    updateHeight(x);
    updateHeight(y);
    
    return y;  // 返回新的根
}

平衡调整

C
// 平衡调整
AVLNode* balance(AVLNode *node) {
    // 先更新当前节点高度
    updateHeight(node);
    
    // 计算平衡因子
    int bf = getBalance(node);
    
    // LL 型: 左子树过高,且左子节点的左子树更高或等高
    if (bf > 1) {
        if (getBalance(node->left) < 0) {
            // LR 型: 先对左子树左旋
            node->left = leftRotate(node->left);
        }
        // 右旋
        return rightRotate(node);
    }
    
    // RR 型: 右子树过高,且右子节点的右子树更高或等高
    if (bf < -1) {
        if (getBalance(node->right) > 0) {
            // RL 型: 先对右子树右旋
            node->right = rightRotate(node->right);
        }
        // 左旋
        return leftRotate(node);
    }
    
    // 已经平衡,直接返回
    return node;
}

插入操作

C
AVLNode* insert(AVLNode *node, int data) {
    // 标准 BST 插入
    if (node == NULL) return createNode(data);
    
    if (data < node->data) {
        node->left = insert(node->left, data);
    } else if (data > node->data) {
        node->right = insert(node->right, data);
    } else {
        // 值已存在,不插入
        return node;
    }
    
    // 平衡调整
    return balance(node);
}

删除操作

C
// 查找最小值节点
AVLNode* findMin(AVLNode *node) {
    while (node->left != NULL) {
        node = node->left;
    }
    return node;
}

// 删除节点
AVLNode* delete(AVLNode *root, int data) {
    if (root == NULL) return NULL;
    
    // 查找要删除的节点
    if (data < root->data) {
        root->left = delete(root->left, data);
    } else if (data > root->data) {
        root->right = delete(root->right, data);
    } else {
        // 找到要删除的节点
        
        // 情况1和2: 有0或1个子节点
        if (root->left == NULL || root->right == NULL) {
            AVLNode *temp = root->left ? root->left : root->right;
            
            if (temp == NULL) {
                // 叶子节点
                temp = root;
                root = NULL;
            } else {
                // 复制子节点内容
                *root = *temp;
            }
            free(temp);
        } else {
            // 情况3: 有两个子节点
            AVLNode *temp = findMin(root->right);
            root->data = temp->data;
            root->right = delete(root->right, temp->data);
        }
    }
    
    // 如果树为空
    if (root == NULL) return NULL;
    
    // 平衡调整
    return balance(root);
}

查找操作

C
AVLNode* search(AVLNode *root, int data) {
    if (root == NULL || root->data == data) {
        return root;
    }
    
    if (data < root->data) {
        return search(root->left, data);
    }
    return search(root->right, data);
}

C++ 模板实现

C++
template<typename T>
class AVLTree {
private:
    struct Node {
        T data;
        int height;
        Node *left, *right;
        Node(T val) : data(val), height(1), left(nullptr), right(nullptr) {}
    };
    
    Node *root;
    
    int height(Node *node) { return node ? node->height : 0; }
    
    int balanceFactor(Node *node) {
        return height(node->left) - height(node->right);
    }
    
    void updateHeight(Node *node) {
        node->height = 1 + std::max(height(node->left), height(node->right));
    }
    
    Node* rotateRight(Node *y) {
        Node *x = y->left;
        y->left = x->right;
        x->right = y;
        updateHeight(y);
        updateHeight(x);
        return x;
    }
    
    Node* rotateLeft(Node *x) {
        Node *y = x->right;
        x->right = y->left;
        y->left = x;
        updateHeight(x);
        updateHeight(y);
        return y;
    }
    
    Node* balance(Node *node) {
        updateHeight(node);
        int bf = balanceFactor(node);
        
        if (bf > 1) {
            if (balanceFactor(node->left) < 0)
                node->left = rotateLeft(node->left);
            return rotateRight(node);
        }
        if (bf < -1) {
            if (balanceFactor(node->right) > 0)
                node->right = rotateRight(node->right);
            return rotateLeft(node);
        }
        return node;
    }
    
    Node* insert(Node *node, T data) {
        if (!node) return new Node(data);
        if (data < node->data) node->left = insert(node->left, data);
        else if (data > node->data) node->right = insert(node->right, data);
        else return node;
        return balance(node);
    }
    
public:
    AVLTree() : root(nullptr) {}
    void insert(T data) { root = insert(root, data); }
    
    bool search(T data) {
        Node *curr = root;
        while (curr) {
            if (data == curr->data) return true;
            curr = data < curr->data ? curr->left : curr->right;
        }
        return false;
    }
};

复杂度分析

时间复杂度

操作 时间复杂度 说明
查找 O(log n) 树高度为 O(log n)
插入 O(log n) 查找 O(log n) + 旋转 O(1)
删除 O(log n) 查找 O(log n) + 旋转 O(log n)
旋转 O(1) 仅修改指针
Text Only
详细分析:

查找:
- AVL树高度 h ≤ 1.44 × log₂(n+2)
- 查找路径最多经过 h 个节点
- 时间复杂度: O(log n)

插入:
- 查找插入位置: O(log n)
- 更新高度: O(log n)(最多更新 h 个节点)
- 旋转调整: O(1)(最多 1 次旋转)
- 总时间复杂度: O(log n)

删除:
- 查找删除节点: O(log n)
- 删除操作: O(log n)
- 平衡调整: O(log n)(最多 h 次旋转)
- 总时间复杂度: O(log n)

旋转次数:
- 插入最多 1 次旋转
- 删除最多 O(log n) 次旋转

空间复杂度

  • O(n):存储 n 个节点
  • 每个节点额外存储高度值:O(1)

AVL树性质

高度上界

Text Only
AVL树高度上界:

定理: 包含 n 个节点的 AVL 树高度 h 满足:
      h ≤ 1.44 × log₂(n + 2) - 0.328

证明:
设 n(h) 为高度为 h 的 AVL 树的最少节点数

递推关系:
- n(0) = 1  (高度为 0 的树只有 1 个节点)
- n(1) = 2  (高度为 1 的树最少有 2 个节点)
- n(h) = n(h-1) + n(h-2) + 1

解释: 要使高度为 h 的 AVL 树节点数最少,左右子树高度应相差 1
      一个子树高度为 h-1,另一个为 h-2

这与 Fibonacci 数列类似,因此:
n(h) ≈ Fibonacci(h+2) - 1 ≈ φ^(h+2) / √5

其中 φ = (1+√5)/2 ≈ 1.618

因此:
n ≥ φ^(h+2) / √5 - 1
h ≤ log_φ(n+1) - 2
h ≤ 1.44 × log₂(n+2) - 0.328

最少节点数

Text Only
高度为 h 的 AVL 树的最少节点数:

h = 0: n(0) = 1
        ┌───┐
        │   │
        └───┘

h = 1: n(1) = 2
        ┌───┐
        │   │
        └───┘
         /
        ┌───┐
        │   │
        └───┘

h = 2: n(2) = n(1) + n(0) + 1 = 4
        ┌───┐
        │   │
        └───┘
       /     \
    ┌───┐   ┌───┐
    │   │   │   │
    └───┘   └───┘
     /
    ...

h = 3: n(3) = n(2) + n(1) + 1 = 7
h = 4: n(4) = n(3) + n(2) + 1 = 12
h = 5: n(5) = n(4) + n(3) + 1 = 20

规律: n(h) ≈ Fibonacci(h+2) - 1

AVL树验证

C
// 验证是否为 AVL 树
int isAVL(AVLNode *root) {
    if (root == NULL) return 1;
    
    // 检查平衡因子
    int bf = getBalance(root);
    if (bf < -1 || bf > 1) return 0;
    
    // 递归检查左右子树
    return isAVL(root->left) && isAVL(root->right);
}

// 验证高度是否正确
int verifyHeight(AVLNode *root) {
    if (root == NULL) return 1;
    
    int expectedHeight = 1 + max(height(root->left), height(root->right));
    if (root->height != expectedHeight) return 0;
    
    return verifyHeight(root->left) && verifyHeight(root->right);
}

AVL vs 红黑树

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    AVL树 vs 红黑树                                  │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  平衡程度:                                                          │
│  ┌─────────────────────┬─────────────────────┐                     │
│  │       AVL树         │       红黑树        │                     │
│  ├─────────────────────┼─────────────────────┤                     │
│  │ 严格平衡             │ 近似平衡            │                     │
│  │ 高度差 ≤ 1          │ 黑高差 ≤ 1          │                     │
│  │ h ≤ 1.44log(n)      │ h ≤ 2log(n+1)       │                     │
│  └─────────────────────┴─────────────────────┘                     │
│                                                                     │
│  查找效率:                                                          │
│  ┌─────────────────────┬─────────────────────┐                     │
│  │       AVL树         │       红黑树        │                     │
│  ├─────────────────────┼─────────────────────┤                     │
│  │ 更优                 │ 稍差               │                     │
│  │ 树更矮               │ 树略高             │                     │
│  │ 查找更快             │ 查找稍慢           │                     │
│  └─────────────────────┴─────────────────────┘                     │
│                                                                     │
│  插入删除:                                                          │
│  ┌─────────────────────┬─────────────────────┐                     │
│  │       AVL树         │       红黑树        │                     │
│  ├─────────────────────┼─────────────────────┤                     │
│  │ 更多旋转             │ 较少旋转            │                     │
│  │ 插入: 最多 1 次      │ 插入: 最多 2 次     │                     │
│  │ 删除: 最多 O(log n)  │ 删除: 最多 3 次     │                     │
│  └─────────────────────┴─────────────────────┘                     │
│                                                                     │
│  实际应用:                                                          │
│  ┌─────────────────────┬─────────────────────┐                     │
│  │       AVL树         │       红黑树        │                     │
│  ├─────────────────────┼─────────────────────┤                     │
│  │ 查找密集型场景       │ 插入删除频繁        │                     │
│  │ 数据库索引           │ STL map/set         │                     │
│  │ 内存数据库           │ Java TreeMap        │                     │
│  │ 编译器符号表         │ Linux进程调度       │                     │
│  └─────────────────────┴─────────────────────┘                     │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
特性 AVL树 红黑树
平衡程度 严格平衡 近似平衡
高度上界 1.44×log(n) 2×log(n+1)
查找效率 更优 稍差
插入旋转 最多 1 次 最多 2 次
删除旋转 最多 O(log n) 次 最多 3 次
空间开销 存储高度 存储颜色
适用场景 查找密集 插入删除频繁

应用场景

1. 数据库索引

Text Only
数据库内存索引:

场景: 需要频繁查询但修改较少的索引

优势:
- 查找效率高,树高度小
- 支持范围查询
- 支持前缀查询

示例:
CREATE INDEX idx_name ON table(column);
- 小型表的内存索引可用 AVL 实现
- 大型表使用 B+ 树(磁盘优化)

2. 内存数据库

Text Only
内存数据库索引:

场景: Redis、MemSQL 等内存数据库

应用:
- 有序集合(Sorted Set)
- 范围查询
- 排名查询

Redis 的 Sorted Set:
- 使用跳表实现(类似 AVL 的查找效率)
- 支持 O(log n) 的插入、删除、查找

3. 编译器符号表

Text Only
编译器符号表实现:

场景: 存储变量、函数、类型等符号信息

操作:
- 插入符号: insert(name, type, scope)
- 查找符号: lookup(name)
- 遍历作用域: traverse(scope)

优势:
- 快速查找符号定义
- 有序遍历符号(按名字排序)
- 支持作用域嵌套

4. 事件调度

Text Only
定时器管理:

场景: 操作系统或应用程序的定时器

实现:
- 按到期时间组织 AVL 树
- 快速找到最早到期的定时器
- 高效插入和删除定时器

操作:
- insert_timer(expire_time, callback)
- find_next_timer() → 最小值
- cancel_timer(id)

5. 文件系统

Text Only
文件系统目录索引:

场景: 需要快速查找文件的目录结构

优势:
- 按文件名排序
- 快速查找文件
- 支持范围列出文件

应用:
- 小型文件系统的内存索引
- 目录缓存

参考资料

  • 《算法导论》第12章 - 二叉搜索树
  • Adelson-Velsky, G. and Landis, E. M. (1962). "An algorithm for the organization of information"
  • LeetCode 110. 平衡二叉树
  • AVL Tree Visualization - cs.usfca.edu