欢迎光临
我们一直在努力

AVL树:自平衡二叉搜索树详解

好的,这是一个关于 平衡二叉树(AVL Tree) 的详细介绍。AVL树是一种自平衡的二叉搜索树(BST),由 G.M. Adelson-Velsky 和 E.M. Landis 在 1962 年提出。它的核心思想是通过维护每个节点的 平衡因子 来确保树的高度保持在 $O(\\log n)$ 级别,从而保证搜索、插入和删除操作的时间复杂度都为 $O(\\log n)$。

1. 平衡因子

AVL树的关键在于 平衡因子(Balance Factor, BF)。对于树中的任意节点 $N$,其平衡因子定义为: $$ \\text{BF}(N) = \\text{height}(\\text{left subtree}) – \\text{height}(\\text{right subtree}) $$ 在AVL树中,要求每个节点的平衡因子必须满足: $$ |\\text{BF}(N)| \\leq 1 $$ 即左子树和右子树的高度差最多为1。

2. 失衡与旋转

当插入或删除节点导致某个节点的平衡因子绝对值大于1时,树就 失衡 了。为了恢复平衡,AVL树使用四种基本的旋转操作:

  • 左旋(Left Rotation):处理右右(RR)失衡
  • 右旋(Right Rotation):处理左左(LL)失衡
  • 先左后右(LR Rotation):处理左右(LR)失衡
  • 先右后左(RL Rotation):处理右左(RL)失衡
旋转操作详解
  • RR 失衡与左旋:当节点A的BF < -1(右子树比左子树高超过1),且其右子节点B的BF <= 0(右子树更高或等高)时,对A进行左旋。
    • 效果:B成为新的根节点,A成为B的左子节点,B原来的左子树(如果有)成为A的右子树。
    • 平衡恢复:调整后,A和B的BF都变为0或接近0。
  • LL 失衡与右旋:当节点A的BF > 1(左子树比右子树高超过1),且其左子节点B的BF >= 0(左子树更高或等高)时,对A进行右旋。
    • 效果:B成为新的根节点,A成为B的右子节点,B原来的右子树(如果有)成为A的左子树。
    • 平衡恢复:调整后,A和B的BF都变为0或接近0。
  • LR 失衡与先左后右旋:当节点A的BF > 1,但其左子节点B的BF < 0(B的右子树更高)时,说明失衡发生在A的左孩子的右子树上。
    • 步骤:先对B进行左旋(将B的右孩子C提升为B的位置),将其转换为LL情况;再对A进行右旋。
  • RL 失衡与先右后左旋:当节点A的BF < -1,但其右子节点B的BF > 0(B的左子树更高)时,说明失衡发生在A的右孩子的左子树上。
    • 步骤:先对B进行右旋(将B的左孩子C提升为B的位置),将其转换为RR情况;再对A进行左旋。

3. 插入操作

AVL树的插入操作在普通BST插入的基础上增加了平衡维护:

  • BST插入:按照二叉搜索树的规则找到合适位置插入新节点。
  • 更新高度:从新插入的节点开始,向上回溯到根节点,更新沿途所有祖先节点的高度。
  • 检查平衡:在回溯过程中,检查每个节点的平衡因子。
  • 旋转调整:如果发现某个节点失衡($|\\text{BF}| > 1$),根据其失衡类型(LL, RR, LR, RL)执行相应的旋转操作,使该子树恢复平衡。旋转后,该子树的高度会发生变化,需要继续向上回溯更新高度和检查平衡,直到根节点。
  • 4. 删除操作

    删除操作比插入更复杂,因为删除节点可能引起多个祖先节点失衡:

  • BST删除:按照二叉搜索树的规则删除目标节点(分三种情况:叶子节点、只有左/右子树、有左右子树)。
  • 更新高度:从被删除节点的父节点(或替代节点)开始,向上回溯到根节点,更新沿途所有祖先节点的高度。
  • 检查平衡与旋转:在回溯过程中,检查每个节点的平衡因子。如果发现失衡,执行相应的旋转操作。注意:一次旋转可能无法完全恢复整棵树的平衡,因为旋转后该子树的高度可能改变,导致其父节点也失衡。因此需要持续回溯到根节点,沿途不断检查和调整。
  • 5. C++ 实现框架

    以下是一个简化的AVL树节点的C++实现框架(未包含完整旋转函数):

    template <typename T>
    class AVLTreeNode {
    public:
    T key;
    AVLTreeNode<T> *left;
    AVLTreeNode<T> *right;
    int height; // 节点高度

    AVLTreeNode(T k) : key(k), left(nullptr), right(nullptr), height(1) {}
    };

    template <typename T>
    class AVLTree {
    private:
    AVLTreeNode<T> *root;

    // 获取节点高度(处理空指针)
    int getHeight(AVLTreeNode<T> *node) {
    return node ? node->height : 0;
    }

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

    // 更新节点高度(基于左右子树高度)
    void updateHeight(AVLTreeNode<T> *node) {
    if (node) {
    node->height = 1 + std::max(getHeight(node->left), getHeight(node->right));
    }
    }

    // 旋转函数 (示例:右旋)
    AVLTreeNode<T>* rightRotate(AVLTreeNode<T> *y) {
    AVLTreeNode<T> *x = y->left;
    AVLTreeNode<T> *T2 = x->right;

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

    // 更新高度 (必须先更新y,再更新x,因为y在x的子树中)
    updateHeight(y);
    updateHeight(x);

    return x; // 返回新的根节点
    }

    // 左旋、LR旋转、RL旋转函数实现类似…

    // 插入辅助函数(递归)
    AVLTreeNode<T>* insert(AVLTreeNode<T> *node, T key) {
    // 1. 标准BST插入
    if (!node) return new AVLTreeNode<T>(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; // 重复键,不插入

    // 2. 更新当前节点高度
    updateHeight(node);

    // 3. 获取平衡因子,检查是否失衡
    int bf = getBalanceFactor(node);

    // 4. 根据失衡类型进行旋转
    // LL Case
    if (bf > 1 && key < node->left->key)
    return rightRotate(node);

    // RR Case
    if (bf < -1 && key > node->right->key)
    return leftRotate(node);

    // LR Case
    if (bf > 1 && key > node->left->key) {
    node->left = leftRotate(node->left);
    return rightRotate(node);
    }

    // RL Case
    if (bf < -1 && key < node->right->key) {
    node->right = rightRotate(node->right);
    return leftRotate(node);
    }

    // 不需要旋转,直接返回当前节点
    return node;
    }

    // 删除辅助函数(递归)实现类似,但更复杂…

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

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

    // 其他成员函数(删除、查找、遍历等)…
    };

    https://www.zhihu.com/zvideo/2010226933791744738
    https://www.zhihu.com/zvideo/2010226743395510262
    https://www.zhihu.com/zvideo/2010226632464540191

    https://www.zhihu.com/zvideo/2010226933791744738
    https://www.zhihu.com/zvideo/2010226743395510262
    https://www.zhihu.com/zvideo/2010226632464540191

    总结

    AVL树通过严格的平衡条件($|\\text{BF}| \\leq 1$)和四种旋转操作,保证了树的高度近似平衡,从而提供了高效的 $O(\\log n)$ 操作。虽然插入和删除时需要额外的旋转开销来维护平衡,但对于查找密集型应用或需要稳定性能的场景,AVL树是一个可靠的选择。理解其平衡因子和旋转机制是掌握该数据结构的关键。

    赞(0)
    未经允许不得转载:171主机测评 » AVL树:自平衡二叉搜索树详解
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址