数据结构:平衡二叉树

一、核心定义

  • 本质 :二叉搜索树(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);
        }
    }
}
相关推荐
Ka1Yan10 分钟前
[二叉树] - 代码随想录:二叉树的统一迭代遍历
数据结构·算法·leetcode
Sheep Shaun20 分钟前
二叉搜索树(下篇):删除、优化与应用
数据结构·c++·b树·算法
鱼鱼块33 分钟前
二叉搜索树:让数据在有序中生长的智慧之树
javascript·数据结构·面试
jianfeng_zhu1 小时前
二叉树的中序线索化,并通过线索化后遍历二叉树
数据结构·链表
C雨后彩虹2 小时前
5G网络建设
java·数据结构·算法·华为·面试
酸菜牛肉汤面2 小时前
5、索引的数据结构(b+树,hash)
数据结构·b树·哈希算法
爱学习的小仙女!4 小时前
顺序表定义、特点和基本操作(含C代码详细讲解)及时间复杂度
数据结构·算法
TechPioneer_lp4 小时前
27届暑期实习内推:网易美团京东快手等
数据结构·c++·人工智能·笔记·机器学习·面试
月明长歌4 小时前
【码道初阶】Leetcode136:只出现一次的数字:异或一把梭 vs HashMap 计数(两种解法完整复盘)
java·数据结构·算法·leetcode·哈希算法
夏乌_Wx5 小时前
练题100天——DAY34:错误的集合+图片平滑器+最长连续递增序列
数据结构