数据结构:平衡二叉树

一、核心定义

  • 本质 :二叉搜索树(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);
        }
    }
}
相关推荐
郝学胜_神的一滴32 分钟前
完全二叉树与堆底层原理深度剖析 | 手写C++大顶堆实现
数据结构·算法
asdzx6733 分钟前
Python 优雅解析 Excel:从原生行列到强类型对象的三层数据结构演进
数据结构·python·excel
是苏浙41 分钟前
Java实现链表2
java·开发语言·数据结构
KobeSacre1 小时前
ThreadLocal 源码
数据结构
少司府1 小时前
C++基础入门:_stack_queue 底层奥秘
开发语言·数据结构·c++·栈和队列·queue·stack
牛油果子哥q1 小时前
unordered_set / unordered_map 底层哈希表精讲,哈希原理、哈希冲突、链地址法、源码结构、有序与无序容器终极选型全解
数据结构·算法·哈希算法·散列表
进击的荆棘1 小时前
优选算法——优先级队列
数据结构·c++·算法·leetcode·优先级队列
牛油果子哥q2 小时前
哈希表经典刷题模型与布隆过滤器精讲,哈希查重、哈希计数、双哈希映射、误判原理与工业级落地应用
数据结构·算法·哈希算法·散列表
2601_961845152 小时前
花生十三图推思维导图|图形推理|技巧
数据结构·算法·链表·贪心算法·排序算法·线性回归·动态规划
前进吧-程序员2 小时前
反转链表完全指南:辅助容器、三指针、头插法
数据结构·c++·链表