AVL树的四种旋转操作用于在插入或删除节点导致二叉树失去平衡

一、平衡二叉树(AVL 树)
设计目的:保证二叉排序树的高度为 $ O(\log_2 n) $,使插入、删除、查找等操作的最坏时间复杂度稳定在 $ O(\log_2 n) $。普通二叉排序树在极端情况下可能退化为链表,导致操作时间复杂度上升至 $ O(n) $。

核心定义:

  • 满足 BST 性质:即对于任意节点,左子树所有节点值小于根节点值,右子树所有节点值大于根节点值。
  • 平衡条件:任一节点的左右子树高度差(称为平衡因子)的绝对值不超过 1。平衡因子 = 左子树深度 - 右子树深度,其值只能是 -1、0 或 1。

高度特性:
含有 $ n $ 个节点的 AVL 树,其最大高度约为 $ 1.44 \log_2 n $,远优于最坏情况下的 $ O(n) $,接近完全二叉树的理想高度 $ \log_2 n $。

为了维持平衡,在插入或删除节点后若出现不平衡(平衡因子变为 ±2),需通过旋转操作(单旋:LL、RR;双旋:LR、RL)进行调整,恢复平衡。


二、线索二叉树(Threaded Binary Tree)
设计目的:解决普通二叉树中无法高效获取某节点在中序遍历中的前驱和后继的问题。同时利用原本浪费的空指针域(n 个节点共有 $ n+1 $ 个空指针)来存储有用的线索信息,提高空间利用率和遍历效率。

实现方式:

  • 将空的左指针改为指向该节点在中序遍历中的前驱节点。
  • 将空的右指针改为指向该节点在中序遍历中的后继节点。
  • 引入两个标志位:
    • ltag:0 表示左指针指向左孩子,1 表示左指针为线索,指向前驱。
    • rtag:0 表示右指针指向右孩子,1 表示右指针为线索,指向后继。

节点结构示例(C语言风格):

struct BTnode {
    int data;
    struct BTnode *left, *right;
    int ltag;   // 0: child, 1: thread (predecessor)
    int rtag;   // 0: child, 1: thread (successor)
};

通过中序线索化后,可以不使用栈或递归实现高效的中序遍历,直接沿线索访问下一个节点。
AVL树的四种旋转操作用于在插入或删除节点导致二叉树失去平衡(即某个节点的平衡因子变为±2)时,恢复其平衡性。这些旋转操作根据失衡节点与其子树中“过高”部分的位置关系分为四类:LL、RR、LR、RL。


一、四种旋转类型及适用场景

类型全称触发条件(以失衡节点为 z场景描述
LL型Left-Leftz 的左子树比右子树高 2,且 z 的左孩子(y)的左子树更高(平衡因子为 +1 或 +2)失衡路径连续向左,形成“左偏左”结构
RR型Right-Rightz 的右子树比左子树高 2,且 z 的右孩子(y)的右子树更高(平衡因子为 -1 或 -2)失衡路径连续向右,“右偏右”结构
LR型Left-Rightz 的左子树过高,但 z 的左孩子的右子树更高先左后右的“Z”字形结构
RL型Right-Leftz 的右子树过高,但 z 的右孩子的左子树更高先右后左的镜像“Z”字形

📌 核心思想:通过一次或两次旋转将“过高”的中间节点提升为新的根,使树重新满足 AVL 平衡条件。


二、旋转操作实现(C语言风格)

假设节点结构如下:

typedef struct AVLNode {
    int data;
    struct AVLNode *left;
    struct AVLNode *right;
    int height; // 存储当前节点高度,便于计算平衡因子
} AVLNode;

辅助函数:获取高度与平衡因子

int max(int a, int b) {
    return (a > b) ? a : b;
}

int height(AVLNode *node) {
    return node == NULL ? 0 : node->height;
}

int getBalance(AVLNode *node) {
    return node == NULL ? 0 : height(node->left) - height(node->right);
}
1. 右单旋(LL旋转)

适用于 LL 型失衡。

AVLNode* rotateRight(AVLNode* y) {
    AVLNode* x = y->left;
    AVLNode* T2 = x->right;

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

    // 更新高度(先更新子节点,再更新父节点)
    y->height = max(height(y->left), height(y->right)) + 1;
    x->height = max(height(x->left), height(x->right)) + 1;

    return x; // 新的根节点
}
2. 左单旋(RR旋转)

适用于 RR 型失衡。

AVLNode* rotateLeft(AVLNode* x) {
    AVLNode* y = x->right;
    AVLNode* T2 = y->left;

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

    // 更新高度
    x->height = max(height(x->left), height(x->right)) + 1;
    y->height = max(height(y->left), height(y->right)) + 1;

    return y; // 新的根节点
}
3. 左右双旋(LR旋转)

先对左孩子左旋(RR),再对根右旋(LL)。

AVLNode* rotateLeftRight(AVLNode* z) {
    z->left = rotateLeft(z->left);  // 左孩子做一次左旋(RR)
    return rotateRight(z);           // 再整体右旋(LL)
}
4. 右左双旋(RL旋转)

先对右孩子右旋(LL),再对根左旋(RR)。

AVLNode* rotateRightLeft(AVLNode* z) {
    z->right = rotateRight(z->right); // 右孩子做一次右旋(LL)
    return rotateLeft(z);              // 再整体左旋(RR)
}

三、插入后的平衡调整逻辑示例

AVLNode* insert(AVLNode* node, int data) {
    // 1. 标准BST插入
    if (node == NULL) {
        AVLNode* newNode = (AVLNode*)malloc(sizeof(AVLNode));
        newNode->data = data;
        newNode->left = newNode->right = NULL;
        newNode->height = 1;
        return newNode;
    }

    if (data < node->data)
        node->left = insert(node->left, data);
    else if (data > node->data)
        node->right = insert(node->right, data);
    else
        return node; // 不允许重复值

    // 2. 更新当前节点高度
    node->height = max(height(node->left), height(node->right)) + 1;

    // 3. 获取平衡因子
    int balance = getBalance(node);

    // 4. 判断失衡类型并旋转调整
    // LL型
    if (balance > 1 && data < node->left->data)
        return rotateRight(node);

    // RR型
    if (balance < -1 && data > node->right->data)
        return rotateLeft(node);

    // LR型
    if (balance > 1 && data > node->left->data) {
        node->left = rotateLeft(node->left);
        return rotateRight(node);
    }

    // RL型
    if (balance < -1 && data < node->right->data) {
        node->right = rotateRight(node->right);
        return rotateLeft(node);
    }

    return node; // 已平衡,返回原节点
}

总结记忆口诀

  • “同方向用单旋”:LL → 右旋,RR → 左旋
  • “异方向用双旋”:LR → 先左旋左孩子,再右旋根;RL → 先右旋右孩子,再左旋根
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bol5261

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值