第十五天PAT-A1123 Is It a Complete AVL Tree平衡二叉树AVL完全二叉树判定背诵模板详细注解

A1123

Description:

给出一组数,求这组数所构成的平衡二叉树的层次遍历序列,并回答其是否为完全二叉树;

思路:

  • 老老实实建树,有关插入部分代码如果有丝毫不理解,强烈建议去找一个动画版本观察,然后自己动手画一画,过程了然于胸之后,再看代码落实,背诵模板如下:

    struct node{
        int v, height;	//height存放该节点子树的最大高度,默认为自己,高度=1
        node *lchild, *rchild;
    };
    node *newNode(int v){
        node* Node = new node;
        Node->v = v;
        Node->height = 1;	//新建节点高度为1
        Node->lchild = Node->rchild = NULL;
        return Node;
    }
    int getHeight(node *root){	//获得root节点子树最大高度
        if(root == NULL) return 0;	//root树不存在返回0
        return root->height;
    }
    int getBalance(node* root){	//获得root节点平衡因子
        return getHeight(root->lchild) - getHeight(root->rchild);//左孩子高度-右孩子高度即为平衡因子
    }
    void updateHeight(node* root){	//更新root节点最大高度,插入节点后立即更新
        root->height = max(getHeight(root->lchild), getHeight(root->rchild))+1;	//更新为左右子树的高度的最大值+1
    }
    void L(node* &root){	//左旋,右侧较高
        node* temp = root->rchild;	//将右孩子暂存
        root->rchild = temp->lchild;	//将右孩子的左孩子给原根右孩子
        temp->lchild = root;	//将原根作为右孩子的左孩子
        updateHeight(root);	//更新原根高度
        updateHeight(temp);	//更新新根(右孩子)高度
        root = temp;	//将指向原根的指针指向新根(右孩子)
    }
    void R(node* &root){	//和左旋完全镜像,左右身份互换
        node* temp = root->lchild;
        root->lchild = temp->rchild;
        temp->rchild = root;
        updateHeight(root);
        updateHeight(temp);
        root = temp;
    }
    void insertNode(node* &root, int v){	//插入新节点
        if(root == NULL){	//树是空的,该节点即放置在该位置
            root = newNode(v);
            return ;
        }
        if(v < root->v){	//小于现根节点
            insertNode(root->lchild, v);	//递归插入至左子树中
            updateHeight(root);	//插入完毕后更新根节点
            if(getBalance(root) == 2){  //根节点==2失衡,即左子树太高
                if(getBalance(root->lchild) == 1){	//左子树==1,即左子树的左子树较高
                    R(root);	//物极必反,简单右旋
                }else if(getBalance(root->lchild) == -1){	//左子树==-1,即左子树的右子树较高
                    L(root->lchild);	//解决局部矛盾,左旋左子树
                    R(root);	//右旋根节点
                }
            }
        }
        else{	//大于现根节点,剩下的操作和小于根节点完全镜像,左右身份互换
            insertNode(root->rchild, v);
            updateHeight(root);
            if(getBalance(root) == -2){
                if(getBalance(root->rchild) == -1){
                    L(root);
                }else if(getBalance(root->rchild) == 1){
                    R(root->rchild);
                    L(root);
                }
            }
        }
    }
    
  • 判断二叉树是否为完全二叉树思路:层次遍历树,根据节点左右子树存在情况进行判断:

    • 若某节点左子树空,则该节点右子树必须为空,否则非完全二叉树;
    • 若某节点左子树空,则该节点往后的节点均不可有非空的左右子树;
    • 若某节点右子树空,则该节点往后的节点同样均不可有非空的左右子树;

    核心代码参考的柳神:

    bool isCom;//isCom用于表示该二叉树是否为完全二叉树,1为是,0为不是
    bool after;//after用于标志往后还能不能有非空节点,1表示可以,0表示不行
    void bfs(node* root){
        queue<node*>q;
        isCom = true;	//初始化,假设为完全二叉树
        after = true;	//可以有非空节点
        q.push(root);	//当前根节点入队
        while(!q.empty()){	
            node* now = q.front();
            ans.push_back(now->v);
            if(now->lchild!=NULL){ //左子树非空
                if(after==false) isCom = false; //判断该左子树是否可以存在,若after==false,则表示该左子树不可存在,标志非完全二叉树
                q.push(now->lchild);
            }else after = false;	//左子树为空,后继将不能再有非空节点
            if(now->rchild!=NULL){	//同上
                if(after==false) isCom = false;
                q.push(now->rchild);
            }else after = false;
            q.pop();
        }
    }
    
  • AC代码

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 25;
int num[maxn], n;
struct node{
    int v, height;	//height存放该节点子树的最大高度,默认为自己,高度=1
    node *lchild, *rchild;
};
node *newNode(int v){
    node* Node = new node;
    Node->v = v;
    Node->height = 1;	//新建节点高度为1
    Node->lchild = Node->rchild = NULL;
    return Node;
}
int getHeight(node *root){	//获得root节点子树最大高度
    if(root == NULL) return 0;	//root树不存在返回0
    return root->height;
}
int getBalance(node* root){	//获得root节点平衡因子
    return getHeight(root->lchild) - getHeight(root->rchild);//左孩子高度-右孩子高度即为平衡因子
}
void updateHeight(node* root){	//更新root节点最大高度,插入节点后立即更新
    root->height = max(getHeight(root->lchild), getHeight(root->rchild))+1;	//更新为左右子树的高度的最大值+1
}
void L(node* &root){	//左旋,右侧较高
    node* temp = root->rchild;	//将右孩子暂存
    root->rchild = temp->lchild;	//将右孩子的左孩子给原根右孩子
    temp->lchild = root;	//将原根作为右孩子的左孩子
    updateHeight(root);	//更新原根高度
    updateHeight(temp);	//更新新根(右孩子)高度
    root = temp;	//将指向原根的指针指向新根(右孩子)
}
void R(node* &root){	//和左旋完全镜像,左右身份互换
    node* temp = root->lchild;
    root->lchild = temp->rchild;
    temp->rchild = root;
    updateHeight(root);
    updateHeight(temp);
    root = temp;
}
void insertNode(node* &root, int v){	//插入新节点
    if(root == NULL){	//树是空的,该节点即放置在该位置
        root = newNode(v);
        return ;
    }
    if(v < root->v){	//小于现根节点
        insertNode(root->lchild, v);	//递归插入至左子树中
        updateHeight(root);	//插入完毕后更新根节点
        if(getBalance(root) == 2){  //根节点==2失衡,即左子树太高
            if(getBalance(root->lchild) == 1){	//左子树==1,即左子树的左子树较高
                R(root);	//物极必反,简单右旋
            }else if(getBalance(root->lchild) == -1){	//左子树==-1,即左子树的右子树较高
                L(root->lchild);	//解决局部矛盾,左旋左子树
                R(root);	//右旋根节点
            }
        }
    }
    else{	//大于现根节点,剩下的操作和小于根节点完全镜像,左右身份互换
        insertNode(root->rchild, v);
        updateHeight(root);
        if(getBalance(root) == -2){
            if(getBalance(root->rchild) == -1){
                L(root);
            }else if(getBalance(root->rchild) == 1){
                R(root->rchild);
                L(root);
            }
        }
    }
}
vector<int>ans;
bool isCom;//isCom用于表示该二叉树是否为完全二叉树,1为是,0为不是
bool after;//after用于标志往后还能不能有非空节点,1表示可以,0表示不行
void bfs(node* root){
    queue<node*>q;
    isCom = true;	//初始化,假设为完全二叉树
    after = true;	//可以有非空节点
    q.push(root);	//当前根节点入队
    while(!q.empty()){
        node* now = q.front();
        ans.push_back(now->v);
        if(now->lchild!=NULL){ //左子树非空
            if(after==false) isCom = false; //判断该左子树是否可以存在,若after==false,则表示该左子树不可存在,标志非完全二叉树
            q.push(now->lchild);
        }else after = false;	//左子树为空,后继将不能再有非空节点
        if(now->rchild!=NULL){	//同上
            if(after==false) isCom = false;
            q.push(now->rchild);
        }else after = false;
        q.pop();
    }
}
int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
    scanf("%d", &n);
    node* root = NULL;
    for(int i = 0; i < n; i++){
        scanf("%d", &num[i]);
        insertNode(root, num[i]);
    }
    bfs(root);
    for(int i = 0; i < ans.size(); i++){
        if(i) printf(" ");
        printf("%d", ans[i]);
    }
    if(isCom) printf("\nYES");
    else printf("\nNO");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值