数据结构:平衡二叉树

一、核心定义

  • 本质 :二叉搜索树(BST)的优化版本,通过限制左右子树的高度差(平衡因子),避免树退化为链表,保障查询、插入、删除操作的时间复杂度稳定在 O(log n)
  • 平衡因子(BF) :节点左子树高度 - 右子树高度(部分实现为绝对值),平衡二叉树要求所有节点的平衡因子满足 |BF| ≤ 1
  • 常见类型:AVL树(严格平衡)、红黑树(近似平衡,工业界常用)、Splay树(自调整平衡)。
  • 资料:https://pan.quark.cn/s/43d906ddfa1bhttps://pan.quark.cn/s/90ad8fba8347https://pan.quark.cn/s/d9d72152d3cf

二、核心特性(以AVL树为例)

  1. 继承BST特性:左子树所有节点值 < 根节点值,右子树所有节点值 > 根节点值,中序遍历为有序序列。
  2. 平衡约束:任意节点的左右子树高度差不超过1。
  3. 动态调整:插入/删除后若平衡被破坏,通过「旋转操作」恢复平衡。

三、平衡破坏与修复(旋转操作)

1. 失衡场景(4种核心情况)

失衡类型 触发条件(以失衡节点为根) 平衡因子特征
左左失衡(LL) 根节点左子树的左子树插入节点 根BF=2,左子树BF=1
右右失衡(RR) 根节点右子树的右子树插入节点 根BF=-2,右子树BF=-1
左右失衡(LR) 根节点左子树的右子树插入节点 根BF=2,左子树BF=-1
右左失衡(RL) 根节点右子树的左子树插入节点 根BF=-2,右子树BF=1

2. 旋转修复方法(可执行步骤)

(1)LL失衡:右旋转
复制代码
# 示例:根节点为A,左子树为B,B的左子树为C
1. 将B的右子树设为A的左子树(若B有右子树);
2. 将A设为B的右子树;
3. 更新A和B的高度(从下往上更新);
4. 将B设为新的根节点。
(2)RR失衡:左旋转
复制代码
# 示例:根节点为A,右子树为B,B的右子树为C
1. 将B的左子树设为A的右子树(若B有左子树);
2. 将A设为B的左子树;
3. 更新A和B的高度;
4. 将B设为新的根节点。
(3)LR失衡:先左旋转再右旋转
复制代码
1. 对根节点的左子树(B)执行左旋转,将LR转化为LL;
2. 对根节点(A)执行右旋转,恢复平衡。
(4)RL失衡:先右旋转再左旋转
复制代码
1. 对根节点的右子树(B)执行右旋转,将RL转化为RR;
2. 对根节点(A)执行左旋转,恢复平衡。

四、核心操作时间复杂度

操作 时间复杂度 说明
查找 O(log n) 树高为log₂n(严格平衡)
插入 O(log n) 最多旋转2次(插入仅影响一条路径)
删除 O(log n) 最多旋转O(log n)次(可能影响多条路径)
高度更新 O(1) 每个节点仅需记录左右子树高度

五、AVL树 vs 红黑树(面试高频对比)

对比维度 AVL树 红黑树
平衡程度 严格平衡( BF
旋转次数 插入最多2次,删除较多 插入最多2次,删除最多3次
空间开销 需存储高度信息(每个节点额外int) 需存储颜色(每个节点额外bit)
适用场景 查询操作远多于插入删除 插入删除频繁(如HashMap、TreeSet)
工业界应用 较少(Redis有序集合早期版本) 广泛(Java集合、Linux内核)

六、代码实现示例(Java:AVL树核心逻辑)

java 复制代码
class AVLNode {
    int val;
    int height; // 节点高度(默认1)
    AVLNode left, right;

    public AVLNode(int val) {
        this.val = val;
        this.height = 1;
    }
}

class AVLTree {
    private AVLNode root;

    // 获取节点高度
    private int getHeight(AVLNode node) {
        return node == null ? 0 : node.height;
    }

    // 计算平衡因子
    private int getBalance(AVLNode node) {
        return node == null ? 0 : getHeight(node.left) - getHeight(node.right);
    }

    // 更新节点高度
    private void updateHeight(AVLNode node) {
        node.height = 1 + Math.max(getHeight(node.left), getHeight(node.right));
    }

    // 右旋转
    private AVLNode rightRotate(AVLNode y) {
        AVLNode x = y.left;
        AVLNode T2 = x.right;

        // 执行旋转
        x.right = y;
        y.left = T2;

        // 更新高度
        updateHeight(y);
        updateHeight(x);

        return x;
    }

    // 左旋转
    private AVLNode leftRotate(AVLNode x) {
        AVLNode y = x.right;
        AVLNode T2 = y.left;

        // 执行旋转
        y.left = x;
        x.right = T2;

        // 更新高度
        updateHeight(x);
        updateHeight(y);

        return y;
    }

    // 插入节点(递归实现)
    public AVLNode insert(AVLNode node, int val) {
        // 1. 执行BST插入
        if (node == null) return new AVLNode(val);
        if (val < node.val) node.left = insert(node.left, val);
        else if (val > node.val) node.right = insert(node.right, val);
        else return node; // 不允许重复值

        // 2. 更新高度
        updateHeight(node);

        // 3. 计算平衡因子,判断是否失衡
        int balance = getBalance(node);

        // 4. 处理4种失衡情况
        // LL
        if (balance > 1 && val < node.left.val)
            return rightRotate(node);
        // RR
        if (balance < -1 && val > node.right.val)
            return leftRotate(node);
        // LR
        if (balance > 1 && val > node.left.val) {
            node.left = leftRotate(node.left);
            return rightRotate(node);
        }
        // RL
        if (balance < -1 && val < node.right.val) {
            node.right = rightRotate(node.right);
            return leftRotate(node);
        }

        return node; // 未失衡,返回原节点
    }

    // 中序遍历(验证有序性)
    public void inorder(AVLNode node) {
        if (node != null) {
            inorder(node.left);
            System.out.print(node.val + " ");
            inorder(node.right);
        }
    }
}
相关推荐
汀、人工智能1 小时前
[特殊字符] 第93课:太平洋大西洋水流问题
数据结构·算法·数据库架构·图论·bfs·太平洋大西洋水流问题
feng_you_ying_li2 小时前
C++11,{}的初始化情况与左右值及其引用
开发语言·数据结构·c++
锅挤2 小时前
数据结构复习(第一章):绪论
数据结构·算法
汀、人工智能3 小时前
[特殊字符] 第95课:冗余连接
数据结构·算法·链表·数据库架构··冗余连接
一只小白0003 小时前
反转单链表模板
数据结构·算法
XiYang-DING3 小时前
【Java】二叉树
java·开发语言·数据结构
坚持编程的菜鸟3 小时前
The Blocks Problem
数据结构·c++·算法
宵时待雨4 小时前
优选算法专题1:双指针
数据结构·c++·笔记·算法·leetcode
汀、人工智能4 小时前
[特殊字符] 第107课:LRU缓存(最后一课[特殊字符])
数据结构·算法·链表·数据库架构·哈希表·lru缓存
每日任务(希望进OD版)4 小时前
线性DP、区间DP
开发语言·数据结构·c++·算法·动态规划