数据结构---平衡二叉树 调整

调整有些术语:

不平衡的发现者:在插入一个结点后,从下往上数的第一个平衡因子(左子树的高度-右子树的高度)变为2或者-2的结点。

麻烦结点:破坏了平衡的结点,就是刚刚插入的结点。

1:LL旋转

需要LL旋转的情况:麻烦结点在不平衡发现者的左子树的左子树上,因而叫LL插入,需要LL旋转;

方法:把不平衡发现者的左儿子提到不平衡发现者的位置,使他成为新的根,而不平衡发现者则插入到之前他左儿子的右儿子上,新根之前的右儿子插入到不平衡发现者的左儿子上面。具体如图:

void LL_Rotate(BBSTree &p)
{  
    BBSTree lc = p->lchild;  // lc指向p结点的左孩子  
    p->lchild = lc->rchild;  // lc结点的右子树置为p结点的左子树  
    lc->rchild = p;          // 置p结点为lc结点的右孩子  
    p = lc;                  // p指向新的根结点  
} 

2:RR旋转:

需要RR旋转的情况:麻烦结点在不平衡发现者的右子树的右子树上,因而叫RR插入,需要RR旋转;

方法:把不平衡发现者的右儿子提到不平衡发现者的位置,使他成为新的根,而不平衡发现者则插入到之前他右儿子的左儿子上,新根之前的左儿子插入到不平衡发现者的右儿子上面。具体如图:

void RR_Rotate(BBSTree &p)
{  
    BBSTree rc = p->rchild;  //rc指向p结点的右孩子  
    p->rchild = rc->lchild;  //rc结点的左子树置为p结点的右子树  
    rc->lchild = p;          //置p结点为rc结点的左孩子  
    p = rc;                  //p指向新的根结点  
} 

3:LR旋转:

需要LR旋转的情况:麻烦结点在不平衡发现者的左子树的右子树上,因而叫LR插入,需要LR旋转;

方法:首先找到以A为根的最小失衡子树,以该子树的左孩子结点B为轴,对右子树结点C进行左旋调整,使之变为LL型。再以C为轴,对不平衡结点A进行右旋调整。

void LR_Rotate(BBSTree &p)
{  
    RR_Rotate(p->lchild);
    LL_Rotate(p);
} 

4:RL旋转:

需要RL旋转的情况:麻烦结点在不平衡发现者的右子树的左子树上,因而叫RL插入,需要RL旋转;

方法:

void RL_Rotate(BBSTree &p)
{  
    LL_Rotate(p->rchild);
    RR_Rotate(p);
} 

简单方法:

不论是LL 还是RR 还是LR 还是RL

以RR的例子为例:

1:找到3个重要的节点:5 10 14
2:对树进行中序排列:4 5 8 10 14 15   查找5 10 14这3个点出现的顺序是5 10 14找到中间位置10
3:上边找到的节点10就是最终的根节点  

typedef struct avltreenode *avltree;
typedef struct avltreenode{
    int data;
    avltree left;
    avltree right;
    int height;
};

int getheight(avltree a)
{
    if(a==NULL) return -1;
    return a->height;
}

//a必须有一个左子结点b
//a与b做左单旋,更新a与b高度,返回新的根结点b
avltree singleleftrotation(avltree a)
{
    avltree b=a->left;
    a->left=b->right;
    b->right=a;
    a->height=max(getheight(a->left),getheight(a->right))+1;
    b->height=max(getheight(b->left),a->height)+1;

    return b;
}

//右单旋
avltree singlerightrotation(avltree a)
{
    avltree b=a->right;
    a->right=b->left;
    b->left=a;

    a->height=max(getheight(a->left),getheight(a->right))+1;
    b->height=max(getheight(b->right),a->height)+1;

    return b;
}

//左右双旋
//a必须有一个左子结点b,且b必须有一个右子结点c
//a,b,c,做两次单旋,返回新的根结点c
//先对b和c做右单旋,在对a和c做左单旋
avltree doubleleftrightrotation(avltree a)
{
    a->left=singlerightrotation(a->left);

    return singleleftrotation(a);
}

//右左双旋
avltree doublerightleftrotation(avltree a)
{
    a->right=singleleftrotation(a->right);

    return singlerightrotation(a);
}

avltree avl_insertion(int x,avltree t)
{
    /*将X插入avl树T中,并返回调整后的avl树*/
    if(!t)/*插入空树,则新建包含一个结点的树*/
    {
        t=(avltree)malloc(sizeof(struct avltreenode));
        t->data=x;
        t->height=0;
        t->left=t->right=NULL;
    }/*插入空树结束*/
    else if(x<t->data)
    {
        t->left=avl_insertion(x,t->left);
        if(getheight(t->left)-getheight(t->right)==2)
        {
            /*需要左旋*/
            if(x<t->left->data)
                t=singleleftrotation(t);//左单旋 singleleftrotation
            else
                t=doubleleftrightrotation(t);//左右双旋
        }
    }
    else if(x>t->data)
    {
        t->right=avl_insertion(x,t->right);
        if(getheight(t->left)-getheight(t->right)==-2)
        {
            /*需要右旋*/
            if(x>t->right->data)
                t=singlerightrotation(t);//右单旋
            else
                t=doublerightleftrotation(t);//右左双旋
        }
    }

    //x=data,无须插入
    t->height=max(getheight(t->left),getheight(t->right))+1;
    return t;
}

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值