平衡二叉查找树(AVL)的构建——左旋右旋

原文链接:https://www.cnblogs.com/ZhaoxiCheung/p/6012783.html

平衡二叉树,又称AVL(Adelson-Velskii和Landis)树,是带有平衡条件的二叉查找树。这个平衡条件必须要容易保持,而且它必须保证树的深度是 O(log N)。

一棵AVL树是其每个节点的左子树和右子树的高度最多差1的二叉查找树( 空树的高度定义为 -1 )。查找、插入和删除在平均和最坏情况下都是 O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。

1、LL型(单次右旋转)

k2的左子树比右子树高2,所以不平衡,我们需要把k1提到k2的位置,然后k2下降到k1的右子树,最后还有把k1的右子树放到k2的左子树即可。
在这里插入图片描述

//LL型旋转(单次右旋)
static Position SingleRotateWithLeft( Position K2 )
{
    Position K1;
 
    K1 = K2->Left;          //找到 K2 左子树
    K2->Left = K1->Right;   //将 K1 右子树移到 K2 的左子树
    K1->Right = K2;         //建立 K1 和 K2 的关系
 
    K2->Height = Max( Height( K2->Left ), Height( K2->Right ) ) + 1;
    K1->Height = Max( Height( K1->Left ), K2->Height ) + 1;
 
    return K1;  /* New root */
}

2、RR型(单次右旋转)

与LL型对称,原理类似
在这里插入图片描述

static Position SingleRotateWithRight( Position K1 )
{
    Position K2;
 
    K2 = K1->Right;
    K1->Right = K2->Left;
    K2->Left = K1;
 
    K1->Height = Max( Height( K1->Left ), Height( K1->Right ) ) + 1;
    K2->Height = Max( Height( K2->Right ), K1->Height ) + 1;
 
    return K2;  /* New root */
}

3、LR型双旋转(单次左旋后右旋)

先以K3的左子树为根节点执行一次左左旋转,然后以k3的根节点,执行一次右右旋转即可。
在这里插入图片描述

static Position DoubleRotateWithLeft( Position K3 )
{
    /* Rotate between K1 and K2 */
    K3->Left = SingleRotateWithRight( K3->Left );
 
    /* Rotate between K3 and K2 */
    return SingleRotateWithLeft( K3 );
}

4、RL型双旋转(单次右旋后单次左旋)

与LR型双旋转对称,原理类似
在这里插入图片描述

static Position DoubleRotateWithRight( Position K1 )
{
    /* Rotate between K3 and K2 */
    K1->Right = SingleRotateWithLeft( K1->Right );
 
    /* Rotate between K1 and K2 */
    return SingleRotateWithRight( K1 );
}

5、结点插入

AVL树进行插入操作时,会破坏二叉树的平衡性,所以每当插入一个数据时,都要从插入点往上,一步一步检测出是否出现平衡因子大于1的,如果有,则要做相应的旋转。

AvlTree Insert( ElementType X, AvlTree T )
{
    if( T == NULL )
    {
        /* Create and return a one-node tree */
        T = malloc( sizeof( struct AvlNode ) );
        if( T == NULL )
            FatalError( "Out of space!!!" );
        else
        {
            T->Element = X;
            T->Height = 0;
            T->Left = T->Right = NULL;
        }
    }
    else if( X < T->Element )                              //插入值比当前结点值小,往左子树插入
    {
        T->Left = Insert( X, T->Left );                    //递归插入
        if( Height( T->Left ) - Height( T->Right ) == 2 )  //判断子树是否平衡
            if( X < T->Left->Element )                     //比当前结点左子树的值小,即为左左情形。
                T = SingleRotateWithLeft( T );             //LL旋转(右单旋转)
            else                                           //否则为左右情形
                T = DoubleRotateWithLeft( T );             //LR旋转
    }
    else if( X > T->Element )                              //插入值比当前结点值大,往右子树插入
    {
        T->Right = Insert( X, T->Right );                  //递归插入
        if( Height( T->Right ) - Height( T->Left ) == 2 )  //判断子树是否平衡
            if( X > T->Right->Element )                    //比当前结点右子树大,即为右右情形
                T = SingleRotateWithRight( T );            //RR旋转(左单旋转)
            else                                           //否则为右左情形
                T = DoubleRotateWithRight( T );            //RL旋转
    }
    /* Else X is in the tree already; we'll do nothing */
 
    T->Height = Max( Height( T->Left ), Height( T->Right ) ) + 1;
    return T;
}

6、结点删除

结点删除包括四种情况:

  • 左右子树都非空
  • 左子树为空,右子树非空
  • 右子树为空,左子树非空
  • 左右子树都为空
AvlTree Delete(ElementType X,AvlTree T)
{
    if (T == NULL)                        //空树直接返回
        return NULL;
    if (x < T->Element)                   //删除值小于当前节点,说明删除节点在当前节点左侧
    {
        T->Left = Delete(X,T->Left);
        if (Height(T->Right) - Height(T->Left) == 2)
        {
            if (Height(T->Right->Left) > Height(T->Right->Right))
                T = DoubleRotateRL(T);
            else
                T = SingleRotateRight(T);
        }
    }
    else if (X > T->Element)             //删除节点在当前节点右侧
    {
        T->Right = Delete(X,T->Right);
        if (Height(T->Left) - Height(T->Right) == 2)
        {
            if (Height(T->Left->Right) > Height(T->Left->Left))
                T = DoubleRotateLR(T);
            else
                T = SingleRotateLeft(T);
        }
    }
    else                                 //找到删除节点
    {
        if (T->Right)                    //右子树不为空的情况
        {
            AvlTree tmp = T->Right;
            while (tmp->Left != NULL) tmp = tmp->Left;  //找到要删除的结点的右子树的左子树最小值,以便替要删除的结点
            T->Element = tmp->Element;
            T->height = tmp->height;
            T->Right = Delete(tmp->Element,T->Right); //递归删除
        }
        else
        {
            //右子树为空的情况,free节点,返回被删除节点的左节点
            //这也是真正删除节点的地方
            AvlTree tmp=T;
            T = T->Left;
            free(emp);
            return T;
        }
    }
    //每次删除之后,都要更新节点的高度
    T->height = Max(Height(T->Left),Height(T->Right)) + 1;
    return T;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值