PAT.1123 Is It a Complete AVL Tree - AVL树

PAT.1123 Is It a Complete AVL Tree - AVL树

题目链接

题目给出插入顺序,要求根据插入顺序构建AVL树,并给出AVL树的层序遍历并判断其是否为完全二叉树。

一边听网课一遍做这道题,一开始想着避免在建树的时候反复搜索高度,于是把树高写成了节点的属性,结果庸人自扰,导致在旋转时涉及了高度更新的代码,浪费了一些时间去想,而且很容易出错。

然后是莫名其妙地,一开始自己在设计节点数据结构的时候做了一个指向父节点的指针,虽然实际求解过程中完全用不到,但是还是像个伞兵一样在旋转的时候写了这个指针的更新策略。

一些尝试

综上两点,写代码的时候出现了大量屎山,虽然最后程序确实能通过样例,但是测试点234仍然不过,于是得分20/30

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;

struct node{
    int val;
    int f;
    node* l;
    node* r;
    node* parent;
    void init(int val){
        this->val = val;
        this->f = 1;
        this->l = nullptr;
        this->r = nullptr;
        this->parent = nullptr;
    }
};

bool isComplete = true,isLastNonLeafAppear = false;
int nodeCnt,tVal;
node* root;
queue<node*> treeLevel;

//左旋
void rotateL(node* subRoot){
    node *rl = subRoot->r->l;
    //先更新f值
    subRoot->f = max((rl == nullptr ? 0 : rl->f),(subRoot->l == nullptr ? 0 : subRoot->l->f)) + 1;
    subRoot->r->f = max((subRoot->r->r == nullptr ? 0 : subRoot->r->r->f),subRoot->f) + 1;

    //subroot parent相关
    subRoot->r->parent = subRoot->parent;
    if(subRoot->parent == nullptr) root = subRoot->r;
    else if(subRoot->parent->l == subRoot) subRoot->parent->l = subRoot->r;
    else if(subRoot->parent->r == subRoot) subRoot->parent->r = subRoot->r;

    subRoot->parent = subRoot->r;
    subRoot->r->l = subRoot;
    subRoot->r = rl;
    if(rl != nullptr) rl->parent = subRoot;
}

//右旋
void rotateR(node* subRoot){
    node *lr = subRoot->l->r;
    //先更新f值
    subRoot->f = max((lr == nullptr ? 0 : lr->f),(subRoot->r == nullptr ? 0 : subRoot->r->f)) + 1;
    subRoot->l->f = max((subRoot->l->l == nullptr ? 0 : subRoot->l->l->f),subRoot->f) + 1;

    //subroot parent相关
    subRoot->l->parent = subRoot->parent;
    if(subRoot->parent == nullptr) root = subRoot->l;
    else if(subRoot->parent->l == subRoot) subRoot->parent->l = subRoot->l;
    else if(subRoot->parent->r == subRoot) subRoot->parent->r = subRoot->l;

    subRoot->parent = subRoot->l;
    subRoot->l->r = subRoot;
    subRoot->l = lr;
    if(lr != nullptr) lr->parent = subRoot;
}

void AVLbalance(node* subRoot,string type){
    type = type.substr(0,2);
    if(type == "LL"){
        rotateR(subRoot);
    }else if(type == "RR"){
        rotateL(subRoot);
    }else if(type == "LR"){
        rotateL(subRoot->l);
        rotateR(subRoot);
    }else if(type == "RL"){
        rotateR(subRoot->r);
        rotateL(subRoot);
    }
}

void AVLinsert(int val){
    node* insertNode = (node*)malloc(sizeof(node));
    insertNode->init(val);
    if(root == nullptr){
        root = insertNode;
        return;
    }
    node *cNode = root,*preNode = nullptr,*imbalanceRoot = nullptr;
    string insertFlag = "L",imbalanceType = "";
    while(cNode != nullptr){
        cNode->f++;
        if(preNode != nullptr && cNode == preNode->l){
            if(abs(cNode->f - (preNode->r == nullptr ? 0 : preNode->r->f)) > 1){
                imbalanceRoot = preNode;
                imbalanceType = "L";
            }
        }else if(preNode != nullptr && cNode == preNode->r){
            if(abs((preNode->l == nullptr ? 0 : preNode->l->f) - cNode->f) > 1){
                imbalanceRoot = preNode;
                imbalanceType = "R";
            }
        }
        preNode = cNode;
        if(val > cNode->val){
            insertFlag = "R";
            cNode = cNode->r;
        }else if(val < cNode->val){
            insertFlag = "L";
            cNode = cNode->l;
        }
        if(imbalanceRoot != nullptr) imbalanceType += insertFlag;
    }
    
    if(insertFlag == "R") preNode->r = insertNode;
    else if(insertFlag == "L") preNode->l = insertNode;
    insertNode->parent = preNode;
    
    if(imbalanceRoot != nullptr) AVLbalance(imbalanceRoot,imbalanceType);
}

int main(){
    cin>>nodeCnt;
    for(int i = 0 ; i < nodeCnt ; ++i){
        cin>>tVal;
        AVLinsert(tVal);
    }
    //完全二叉树的检查,不存在只有右孩子的节点,只有左孩子的节点或叶子结点出现后只能出现叶子节点
    treeLevel.push(root);
    while(!treeLevel.empty()){
        node* cNode = treeLevel.front();
        cout<<cNode->val;
        treeLevel.pop();
        if(cNode->l != nullptr){
            if(isLastNonLeafAppear) isComplete = false;
            treeLevel.push(cNode->l);
            if(cNode->r == nullptr) isLastNonLeafAppear = true;
        }
        if(cNode->r != nullptr){
            if(isLastNonLeafAppear) isComplete = false;
            treeLevel.push(cNode->r);
            if(cNode->l == nullptr) isComplete = false;
        }
        if(cNode->l == nullptr && cNode->r == nullptr) isLastNonLeafAppear = true;
        if(treeLevel.size() != 0) cout<<' ';
    }
    cout<<endl<<(isComplete ? "YES" : "NO")<<endl;
}

题解

整理了思路然后重新写了一遍:

不用变量维护树的高度是要付出代价的————每次判断节点是否失衡都要搜索当前节点左右子树的深度,虽然用递归也很好实现。

递归建树也是要付出代价的————每次插入节点都会更新插入路径上所有的连接关系,虽然这道题最多只有20个节点。

那就这样吧,每次插入节点都用递归自底向上更新一遍节点的连接关系,在更新的同时搜索当前节点左右子树的深度,如果当前节点失衡就对当前节点为根的树进行旋转,然后将新的根节点返回,以供给高层节点建立连接。

这样操作每次插入节点,最外层的递归函数返回的总是整棵树的根,所以不断插入、不断记录根节点即可。

最后判断完全二叉树,因为建树的时候用了链式结构,这里不能直接用顺序存储下标判断的方法,所以要么层序遍历树,将链式关系存储到线性空间,然后用下标判断,要么想想完全二叉树的特点,然后用一定的规律来判断。

大概想了一下是这样的:

  • 完全二叉树中不存在只有右孩子的节点
  • 在层序遍历的过程中,一旦出现只有左孩子的节点或者叶子节点后,后续的节点必须都是叶子结点

然后用这两个条件判断一下就完事儿了。

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;

struct node{
    int val;
    node* l;
    node* r;
    node(){
        l = r = nullptr;
    }
    node(int t){
        val = t;
        l = r = nullptr;
    }
};

bool isComplete = true,isLastNonLeafAppear = false;
int nodeCnt,tVal;
node* root;
queue<node*> treeLevel;

int getTreeDepth(node* cNode){
    if(cNode == nullptr) return 0;
    return max(getTreeDepth(cNode->l),getTreeDepth(cNode->r)) + 1;
}

//左旋
node* rotateL(node* subRoot){
    node* t = subRoot->r;
    subRoot->r = t->l;
    t->l = subRoot;
    return t;
}

//右旋
node* rotateR(node* subRoot){
    node* t = subRoot->l;
    subRoot->l = t->r;
    t->r = subRoot;
    return t;
}

//递归建立AVL,返回当前节点以供上一层建立连接
node* build(int val,node* cNode){
    if(cNode == nullptr){
        cNode = new node(val);
        return cNode;
    }
    if(val > cNode->val){
        cNode->r = build(val,cNode->r);
        if(abs(getTreeDepth(cNode->l) - getTreeDepth(cNode->r)) > 1){
            if(val > cNode->r->val){
                //RR
                cNode = rotateL(cNode);
            }else if(val < cNode->r->val){
                //RL
                cNode->r = rotateR(cNode->r);
                cNode = rotateL(cNode);
            }
        }
    }else if(val < cNode->val){
        cNode->l = build(val,cNode->l);
        if(abs(getTreeDepth(cNode->l) - getTreeDepth(cNode->r)) > 1){
            if(val < cNode->l->val){
                //LL
                cNode = rotateR(cNode);
            }else if(val > cNode->l->val){
                //LR
                cNode->l = rotateL(cNode->l);
                cNode = rotateR(cNode);
            }
        }
    }
    return cNode;
}

int main(){
    cin>>nodeCnt;
    for(int i = 0 ; i < nodeCnt ; ++i){
        cin>>tVal;
        root = build(tVal,root);
    }
    treeLevel.push(root);
    while(!treeLevel.empty()){
        node* cNode = treeLevel.front();
        cout<<cNode->val;
        treeLevel.pop();
        if(cNode->l != nullptr){
            if(isLastNonLeafAppear) isComplete = false;
            treeLevel.push(cNode->l);
            if(cNode->r == nullptr) isLastNonLeafAppear = true;
        }
        if(cNode->r != nullptr){
            if(isLastNonLeafAppear) isComplete = false;
            treeLevel.push(cNode->r);
            if(cNode->l == nullptr) isComplete = false;
        }
        if(cNode->l == nullptr && cNode->r == nullptr) isLastNonLeafAppear = true;
        if(treeLevel.size() != 0) cout<<' ';
    }
    cout<<endl<<(isComplete ? "YES" : "NO")<<endl;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值