数据结构:平衡二叉树

一、核心定义

  • 本质 :二叉搜索树(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);
        }
    }
}
相关推荐
Undergoer_TW37 分钟前
20251204_线程安全问题及STL数据结构的存储规则
数据结构·c++·哈希算法
9523640 分钟前
并查集 / LRUCache
数据结构·算法
potato_may9 小时前
链式二叉树 —— 用指针构建的树形世界
c语言·数据结构·算法·链表·二叉树
Mz12219 小时前
day07 和为 K 的子数组
数据结构
Albert Edison11 小时前
【项目设计】C++ 高并发内存池
数据结构·c++·单例模式·哈希算法·高并发
小许学java14 小时前
数据结构-模拟实现顺序表和链表
java·数据结构·链表·arraylist·linkedlist·顺序表模拟实现·链表的模拟实现
稚辉君.MCA_P8_Java15 小时前
Gemini永久会员 C++返回最长有效子串长度
开发语言·数据结构·c++·后端·算法
dragoooon3416 小时前
[优选算法专题十.哈希表 ——NO.55~57 两数之和、判定是否互为字符重排、存在重复元素]
数据结构·散列表
稚辉君.MCA_P8_Java17 小时前
Gemini永久会员 go数组中最大异或值
数据结构·后端·算法·golang·哈希算法