PAT甲级1066 Root of AVL Tree (25分):[C++题解]建立平衡树(AVL树)

题目分析

在这里插入图片描述
在这里插入图片描述
图片来源:acwing
分析
平衡树(AVL树)是平衡二叉搜索树的简称,当然需要满足二叉搜索树的性质,左子树小于根,根小于等于右子树;然后还要满足平衡树的基本特性,就是任意一个结点的左右子树高度之差不超过1.

不平衡的BST可以经过左旋或者右旋变成新的平衡树。左旋和右旋只是改变树的结构,不会改变树的中序遍历结果

以下图说明右旋的过程,实际上,下图已经是平衡树,不用旋转。仍然可以说明右旋的具体操作。下图中L[]数组表示左儿子,R[]数组表示右儿子。

右旋分为三步:1)B变成根;2)A变成B的右孩子;3)把E变成A的左孩子。

在这里插入图片描述
实现右旋的代码如下:其中update是一个函数,用来计算结点高度。请读者对照上图阅读本代码。

/*
右旋
u 是结点
*/
void R(int& u){
    int p =l[u]; //左儿子记为p
    l[u] =r[p];//p的右儿子(E)变成原来根(A)的左儿子
    r[p] = u;  //新根的右儿子是原来的根u
    update(u),update(p); //重新计算高度
    u = p; //根结点变成左儿子p
}

将右图转化为左图就是左旋,如下图。

在这里插入图片描述
左旋代码:和右旋正好对称,将l和r互换即可。

void L(int& u){
    int p = r[u];//右儿子(图中的A)记p
    r[u] = l[p]; //p(图中的A)的左儿子(图中的E)变成原来根(图中的B)的右儿子
    l[p] = u; //原来的根(图中的B)变成p(图中的A)的左儿子
    update(u),update(p); //重新计算结点的高度
    u = p;
}

ac代码
四种情况如下图,insert()函数用来构造AVL树,以A为树根。

如果if(get_balance(u) == -2),表示 右子树比左子树高度高2,可以有两种情况。 先取A的右孩子B,第一种是如果if(get_balance(u) == -1) 即B的右子树高度比左子树高1,即情况[2],此时左旋A;另一种是B的左子树高度比右子树高1,即情况[4].此时先右旋B,再左旋A

如果if(get_balance(u) == 2) 表示左子树高度比右子树高2,可以分为两种情况。先取A的左儿子B。第一种情况是如果if(get_balance(u) ==1) 表示B的左子树比右子树高度高1,即情况[1],此时右旋A; 另一种是B的右子树比左子树高1,即情况[3].此时先左旋B,再右旋A
在这里插入图片描述


#include<bits/stdc++.h>
using namespace std;

const int N = 40;
int l[N],r[N],v[N];//权值 
int n;
int h[N];//高度
int idx; 

/*update求每一结点的高度

*/
void update(int u){
    h[u] =max(h[l[u]] , h[r[u]]) + 1;
}

/*
右旋
u 是结点
*/
void R(int& u){
    int p =l[u]; //左儿子成为新的根
    l[u] =r[p];//根的左儿子变成
    r[p] = u;  //新根的右儿子是原来的根u
    update(u),update(p); //重新计算高度
    u = p; //根结点变成左儿子p
}

/*
左旋
u是结点
*/
void L(int& u){
    int p = r[u];//右儿子成为新根
    r[u] = l[p];
    l[p] = u;
    update(u),update(p);
    u = p;
}
/*
get_balance左子树和右子树高度差
*/
int get_balance(int u){
    return h[l[u]] -h[r[u]];  
}

/*
insert建平衡树
1.二叉搜索树
2.高度差≤1
*/
void insert(int &u, int w){
    
    if(u==0){
        u =++idx;
        v[u] =w;
    }
    else if(w< v[u]){
        
        insert(l[u],w);
        //左子树比右子树高2 情况[1]
        if(get_balance(u) ==2){
            //以左儿子为根,其左子树以右子树高1
             if(get_balance(l[u]) ==1) R(u);
             //以左儿子为根,其右子树比左子树高1 如情况[3]
             else L(l[u]),R(u);
        }
        
    } 
    else {
        insert(r[u],w);
        //右子树比左子树高2 如情况[2]
        if(get_balance(u) == -2){
            //以右儿子为根,其右子树比左子树高1,
            if(get_balance(r[u]) == -1) L(u);
            //以右儿子为根,其左子树比右子树高1
            else R(r[u]),L(u);
        }
    }
    update(u); //求u结点的高度
}

int main(){
    cin >> n;
    int root =0;
    while(n--){
        int w;
        cin>> w;
        insert(root ,w);
    }
    //输出avl树根
    cout<<v[root]<<endl;    
}

题目链接

PAT甲级1066 Root of AVL Tree (25分)

acwing1552. AVL树的根

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页