平衡二叉树


平衡二叉树(Balanced Binary Tree)介绍

平衡二叉树(Balanced Binary Tree)是一种特殊的二叉搜索树(BST),它在 插入、删除操作后仍能保持高度平衡,从而保证查找、插入、删除的时间复杂度为 O(log n)


1. 为什么需要平衡二叉树?

普通二叉搜索树(BST)的问题:

  • 最坏情况下可能退化为链表,导致查找效率从 O(log n) 变为 O(n)

  • 例如,对于以下

    有序插入的情况:

    1
     \
      2
       \
        3
         \
          4

    这里的 BST 退化成了一条 单链表,查找效率大大降低。

平衡二叉树的目标:

  • 保证 任意节点的左右子树高度差不超过一定范围,确保树的高度保持在 O(log n),从而提高查找效率。

2. 常见的平衡二叉树类型

(1) AVL 树

特点

  • AVL 树是 最早提出的自平衡二叉搜索树(1962 年)。
  • 任何节点的 左右子树高度差不超过 1
  • 通过 旋转(左旋、右旋、双旋) 保持平衡。

缺点

  • 插入和删除时的 调整次数较多,维护成本较高。
  • 适用于 查找较多,插入/删除较少的场景(如数据库索引)。

(2) 红黑树(Red-Black Tree)

特点

  • 每个节点要么是红色,要么是黑色
  • 通过颜色变化+旋转维持平衡,保证最长路径不超过最短路径的 2 倍。
  • 适用于 插入、删除频繁 的场景(如 STL 的 mapset)。

对比 AVL 树

  • AVL 树查找更快(更严格平衡),但插入/删除调整较多。
  • 红黑树插入/删除更快,适用于动态数据结构。

(3) Treap(树堆)

特点

  • 结合了 二叉搜索树(BST)和 堆(Heap) 的特性:
    • BST:按照键值(key)排序,左子树 < 根 < 右子树。
    • :按照优先级(priority)排序,父节点优先级高于子节点。
  • 插入时随机分配 优先级,通过旋转维持平衡。

优点

  • 实现简单,适用于 随机化数据结构,常用于 竞赛和高效算法

(4) Splay 树

特点

  • 自调整二叉搜索树:每次访问某个节点时,会通过 旋转 使该节点成为根。
  • 访问频繁的节点会更接近根,提高局部查找速度(自适应特性)。

应用场景

  • 缓存系统(LRU 实现)、字符串搜索(如 Rope 数据结构)

3. AVL 树的实现

AVL 树的核心操作

  1. 旋转操作(保持平衡):
    • 左旋(Left Rotation)
    • 右旋(Right Rotation)
    • 左右双旋(Left-Right Rotation)
    • 右左双旋(Right-Left Rotation)
  2. 插入操作:
    • 插入后,可能导致不平衡,需要 旋转恢复平衡
  3. 删除操作:
    • 删除节点后,也可能导致不平衡,需要 旋转恢复平衡

C++ AVL 树实现

#include <iostream>

using namespace std;

struct Node {
    int key;
    int height;
    Node* left;
    Node* right;

    Node(int val) : key(val), height(1), left(nullptr), right(nullptr) {}
};

class AVLTree {
private:
    Node* root;

    // 获取节点高度
    int getHeight(Node* node) {
        return node ? node->height : 0;
    }

    // 计算平衡因子
    int getBalanceFactor(Node* node) {
        return node ? getHeight(node->left) - getHeight(node->right) : 0;
    }

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

    // 左旋
    Node* leftRotate(Node* x) {
        Node* y = x->right;
        x->right = y->left;
        y->left = x;
        updateHeight(x);
        updateHeight(y);
        return y;
    }

    // 右旋
    Node* rightRotate(Node* y) {
        Node* x = y->left;
        y->left = x->right;
        x->right = y;
        updateHeight(y);
        updateHeight(x);
        return x;
    }

    // 插入节点
    Node* insert(Node* node, int key) {
        if (!node) return new Node(key);

        if (key < node->key)
            node->left = insert(node->left, key);
        else if (key > node->key)
            node->right = insert(node->right, key);
        else
            return node;

        updateHeight(node);

        // 平衡因子
        int balance = getBalanceFactor(node);

        // LL型(右旋)
        if (balance > 1 && key < node->left->key)
            return rightRotate(node);

        // RR型(左旋)
        if (balance < -1 && key > node->right->key)
            return leftRotate(node);

        // LR型(左-右旋)
        if (balance > 1 && key > node->left->key) {
            node->left = leftRotate(node->left);
            return rightRotate(node);
        }

        // RL型(右-左旋)
        if (balance < -1 && key < node->right->key) {
            node->right = rightRotate(node->right);
            return leftRotate(node);
        }

        return node;
    }

    // 中序遍历
    void inorder(Node* node) {
        if (!node) return;
        inorder(node->left);
        cout << node->key << " ";
        inorder(node->right);
    }

public:
    AVLTree() : root(nullptr) {}

    void insert(int key) {
        root = insert(root, key);
    }

    void display() {
        inorder(root);
        cout << endl;
    }
};

int main() {
    AVLTree tree;
    tree.insert(10);
    tree.insert(20);
    tree.insert(30);
    tree.insert(25);
    tree.insert(5);
    tree.insert(15);

    tree.display();
    return 0;
}

4. 总结

  • AVL 树保证平衡性,适用于 查找操作频繁的场景
  • 红黑树适用于动态插入/删除操作,如 STL 的 map/set
  • Splay 树自适应局部访问,适合 缓存(LRU)
  • Treap 结合了 BST 和堆,适合 随机数据结构

不同平衡二叉树的选择

  • 查找多、插入少AVL 树
  • 插入、删除频繁红黑树
  • 局部访问频繁Splay 树
  • 随机化结构Treap

红黑树和 AVL 树是最常见的 高效平衡二叉树,了解它们能帮助更好地设计高效的数据结构!


文章作者: Gustavo
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明来源 Gustavo !
评论
  目录