平衡二叉树详解

AVL树是最先发明的自平衡二叉查找算法,是平衡二叉树的一种。在AVL中任何节点的两个儿子子树的高度最大差别为1,所以它又被成为高度平衡树。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来平衡这棵树。

转载链接:手把手教你写平衡二叉树_dreamzuora的博客-CSDN博客_二叉树伪代码

假设把AVL树构造过程中需要重新平衡的节点叫做α。由于任意节点最多有两个儿子,因此高度不平衡时,α点的两颗子树的高度差2。这种不平衡可能出现在下面这四种情况:

1)  对α的左儿子的左子树进行一次插入(左旋)

其中D是新插入的节点,红色节点K2是失去平衡的节点。需要对K1和K2进行左旋调整即将K1作为根,将K2作为K1的左子树,K1的右子树调整为K2的左子树。如下图所示

进行左旋变换   

node* L_Ratate(node *K2)  //左旋  
{  
    node *K1;  
    K1 = K2->Left;  
    K2->Left = K1->Right;  
    K1->Right = K2;  
    //更新节点的高度  
    return K1;  
}  

2)对α的右儿子的右子树进行一次插入(右旋)

将K2的右子树更改为K1的左子树,K1的左子树更改为K2即完成的右旋,如下图所示

进行右旋

node* R_Ratate(node* K2)  
{  
    node* K1;  
    K1 = K2->Right;  
    K2->Right = K1->Left;  
    K1->Left = K2;  
    //更新节点高度  
    return K1;  
}  

3)对α的右儿子的左子树进行一次插入(右左双旋)

右左双旋:先对K1和K2进行左旋,然后在对K2和K3进行右旋,最终实现平衡。如下图所示

进行一次左旋进行一次右旋

node* DoubleL_Rotate(node* K3)//双向旋转(左右)  
{  
    K3->Left = R_Ratate(K3->Left);  
    return L_Ratate(K3);  
}  

4)对α的左儿子的右子树进行一次插入(左右双旋)

左右双旋这里的左右指的是对α的左儿子的右子树进行插入时需要旋转。先对K1和K2进行右旋(跟第四种情况类似),然后再对K3和K2进行左旋,最终实现平衡。如下图所示

进行一次右旋进行一次左旋

node* DoubleR_Rotate(node* K3)//双向旋转(右左)  
{  
    K3->Right = L_Ratate(K3->Right);  
    return R_Ratate(K3);  
}  


完整代码:

#include<iostream>  
#include<algorithm>  
using namespace std;  
typedef struct Node  
{  
    int data;  
    int bf;//用来表示平衡因子  
    struct Node *Left,*Right;  
} node;  
node* L_Ratate(node *K2)  //左旋  
{  
    node *K1;  
    K1 = K2->Left;  
    K2->Left = K1->Right;  
    K1->Right = K2;  
    //更新节点的高度  
    return K1;  
}  
node* R_Ratate(node* K2)  
{  
    node* K1;  
    K1 = K2->Right;  
    K2->Right = K1->Left;  
    K1->Left = K2;  
    //更新节点高度  
    return K1;  
}  
node* DoubleL_Rotate(node* K3)//双向旋转(左右)  
{  
    K3->Left = R_Ratate(K3->Left);  
    return L_Ratate(K3);  
}  
node* DoubleR_Rotate(node* K3)//双向旋转(右左)  
{  
    K3->Right = L_Ratate(K3->Right);  
    return R_Ratate(K3);  
}  
int Height(node* P)  
{  
    if(P == NULL)  
        return -1; //当构建根节点,或者是叶子节点的时候为-1+1正好为0  
    else  
        return P->bf;  
}  
  
  
node* create_bst(node* bst,int x)  
{  
    //cout<<"ok\n";  
    if(!bst)  
    {  
        //cout<<"ok\n";  
        bst=new node;  
        bst->data=x;  
        bst->bf=0;  
        bst->Left=bst->Right=NULL;  
    }  
    else if(x<bst->data)  
    {  
        bst->Left=create_bst(bst->Left,x);  
        if(Height(bst->Left)-Height(bst->Right)==2)//左子树插入节点所以高度是左子树高于右子树  
        {  
            if(x<bst->Left->data)//对α的左儿子的左子树进行一次插入,需要左旋  
                bst=L_Ratate(bst);  
            else//对α的左儿子的右子树进行一次插入,需要双旋  
                bst=DoubleL_Rotate(bst);  
        }  
    }  
    else if(x>bst->data)//右子树插入新节点  
    {  
        bst->Right = create_bst(bst->Right,x);  
        if(Height(bst->Right) - Height(bst->Left)== 2)//因为是右子树插入新节点,所以高度是右子树高于左子树  
        {  
            if(x > bst->Right->data)//对α的右儿子的右子树进行一次插入,需要右旋  
                bst = R_Ratate(bst);  
            else//对α的右儿子的左子树进行一次插入,需要双旋  
                bst = DoubleR_Rotate(bst);  
        }  
    }  
    bst->bf = max(Height(bst->Left), Height(bst->Right)) + 1;  
   //cout<<"test="<<bst->bf<<endl;  
    return bst;  
}  
void InOrder(node* bst)  
{  
    if(!bst)  
        return;  
    else  
    {  
        InOrder(bst->Left);  
        cout<<bst->data<<' '<<endl;  
        InOrder(bst->Right);  
    }  
}  
int main()  
{  
    int n;  
    cout<<"请输入要构建的二叉平衡树序列长度"<<endl;  
    cin>>n;  
    cout<<"请输入要构建的二叉平衡树序列"<<endl;  
    node *bst=NULL;  
    for(int i=0; i<n; ++i)  
    {  
        int d;  
        cin>>d;  
        bst=create_bst(bst,d);  
    }  
    cout<<"....输出...."<<endl;  
    InOrder(bst);  
    return 0;  
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值