平衡二叉树(AVL树)的平衡原理以及插入,删除操作


AVL树的定义

平衡因子 : 树中某结点其左子树的高度和右子树的高度之差
AVL树中的任意一个结点, 其平衡因子绝对值小于2
AVL树是一种特殊的二叉搜索树 (BST树), 相对于数据极端情况下, 二叉搜索树会退化成为单链表, AVL树定义了旋转操作, 在平衡因子大于等于2时, AVL树会旋转来调整树的结构, 来重新满足平衡因子小于2

在这里插入图片描述

这两棵树, 右边的为AVL树

现在定义AVL树结构如下:

struct AVLNode 
{
    AVLNode() 
        : val(0), left(nullptr), right(nullptr) 
    {}
    AVLNode(int v)
        : val(v), left(nullptr), right(nullptr)
    {}
    int val;    //data
    // int height;  //当前结点高度
    AVLNode* left;
    AVLNode* right;
};

AVL树不平衡的情况

AVL树大部分操作都和BST树相同, 只有在插入删除结点时, 有可能造成AVL树失去平衡, 而且只有那些在被插入/删除结点到根节点的路径上的结点有可能出现失衡, 因为只有那些结点的子树结构发生了变化

当插入新结点导致不平衡时, 我们需要找到距离新节点最近的不平衡结点为轴来转动AVL树来达到平衡

左子树的左子树插入结点 (左左)

在这里插入图片描述
向该AVL树添加结点 1, 导致结点 6 失衡 ( 结点 2 相对于结点 6 为左子树的左子树), 那么就旋转结点 6, 使其平衡因子重新满足AVL树条件

//左左情况旋转(t是失衡结点)
    void LL(AVLNode** t) 
    {
        if (t != nullptr)
        {
            AVLNode* tmpPtr = (*t)->left;
            (*t)->left = tmpPtr->right;    //t左子树的右子树作为t的左子树
            tmpPtr->right = *t;
            *t = tmpPtr;
        }
    }

右子树的右子树插入节点 (右右)

在这里插入图片描述

 //右右情况旋转
    void RR(AVLNode** t)
    {
        if (t != nullptr) 
        {
            AVLNode* tmpPtr = (*t)->right;
            (*t)->right = tmpPtr->left;
            tmpPtr->left = *t;
            *t = tmpPtr;
        }
    }

左子树的右子树插入节点 (左右)

在这里插入图片描述
结点 8 的左子树的右子树位置插入结点 6, 结点 8 失衡, 这时需要先将失衡节点 8 的左子树进行"右右"情况旋转, 然后再对结点 8 进行"左左"情况旋转

//左右情况旋转 (t为失衡结点,新节点位于t的左子树的右子树)
    void LR(AVLNode** t) 
    {
        RR(&(*t)->left);
        LL(t);
    }

右子树的左子树插入节点 (右左)

在这里插入图片描述
插入结点 12 时失衡, 失衡结点 10 结点, 新结点是其右子树的右子树, 这时需要先将其右子树按"左左"情况向右旋转, 再按"右右"情况向左先旋转

//右左情况旋转
    void RL(AVLNode** t) 
    {
        LL(&(*t)->right);
        RR(t);
    }

删除结点

AVL树是一种特殊的二叉搜索树, 所以要考虑的情况和BST树删除结点一样, 不同的是删除一个结点有可能引起父结点失衡, 所以我们需要在每次回退的时候计算结点高度

关于二叉搜索树具体如何删除结点

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值