PAT A1123 Is It a Complete AVL Tree (30分) (AVL树 和 CBT判定)

PAT甲级:A1123 Is It a Complete AVL Tree (30分)

An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.

F1.jpgF2.jpg
F3.jpgF4.jpg

Now given a sequence of insertions, you are supposed to output the level-order traversal sequence of the resulting AVL tree, and to tell if it is a complete binary tree.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N (≤ 20). Then N distinct integer keys are given in the next line. All the numbers in a line are separated by a space.

Output Specification:

For each test case, insert the keys one by one into an initially empty AVL tree. Then first print in a line the level-order traversal sequence of the resulting AVL tree. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line. Then in the next line, print YES if the tree is complete, or NO if not.

Sample Input 1:

5
88 70 61 63 65 

Sample Output 1:

70 63 88 61 65
YES

Sample Input 2:

8
88 70 61 96 120 90 65 68   

Sample Output 2:

88 65 96 61 70 90 120 68
NO
  • 题意:给定插入结点的顺序,将其构建成平衡二叉树,输出这棵AVL树的层序遍历序列,并判断这棵树是不是完全二叉树。
  • 分析:这题考察的是AVL树的构建和以及完全二叉树的判定。
  1. AVL本身是二叉搜索树,为了防止出现一边倒的情况,在插入结点到二叉搜索树的同时,对这棵树做相应调整,使这棵树的任意子树均保持左右子树高度差不超过1的特性。
  2. 对树的调整有4种形态。FIgure1所示,则直接从根节点右旋即可;Figure2所示,则是以88为根的结点需要左旋,而根结点70不需要调整;Figure3所示,则是先将以96为根的子树做右旋,把它调整为右侧较重的形状,之后对70为根的树左旋,刚好又能变得平衡;Figure4则是对以70为根的子树做右旋。
  3. AVL树构建完成后,层序遍历则是BFS这棵树就行了,这里还要解决问题的是在层序遍历的同时对其是否为完全二叉树做判断。因为这里事先就知道这棵树的结点数了,在对结点做输出的时候,每输出一个结点,cnt就会加1,这里对任意非叶子结点不管其左右孩子谁为空,都将其放进队列中,那么如果是完全二叉树,在遍历的过程中,即cnt未到达n的时队列中一定不会出现NULL元素,由此便可判断其是否为完全二叉树了。
#include <bits/stdc++.h>
using namespace std;
struct node {
    int data, height;
    node *left, *right;
    node(int x) : data(x) {
        height = 1;
        left = right = NULL;
    }
};
int getHeight(node *root) {
    if (root == NULL) return 0;
    return root->height;
}
void updateHeight(node *root) {
    root->height = max(getHeight(root->left), getHeight(root->right)) + 1;
}
int getBalanceFactor(node *root) {
    return getHeight(root->left) - getHeight(root->right);
}
void L(node *&root) {
    node *temp = root->right;
    root->right = temp->left;
    temp->left = root;
    updateHeight(root);
    updateHeight(temp);
    root = temp;
}
void R(node *&root) {
    node *temp = root->left;
    root->left = temp->right;
    temp->right = root;
    updateHeight(root);
    updateHeight(temp);
    root = temp;
}
void insert(node *&root, int x) {
    if (root == NULL) {
        root = new node(x);
        return;
    }
    if (x < root->data) {
        insert(root->left, x);
        updateHeight(root);
        if (getBalanceFactor(root) == 2) {
            if (getBalanceFactor(root->left) == -1) L(root->left);
            R(root);
        }
    } else {
        insert(root->right, x);
        updateHeight(root);
        if (getBalanceFactor(root) == -2) {
            if (getBalanceFactor(root->right) == 1) R(root->right);
            L(root);
        }
    }
}
void bfs(node *root, int n) {
    queue<node *> q;
    q.push(root);
    int iscbt = 1, cnt = 0;
    while (!q.empty()) {
        node *now = q.front();
        q.pop();
        if (cnt < n && now == NULL) iscbt = false;
        if (now) {
            printf("%d", now->data);
            if (++cnt < n) printf(" ");
            q.push(now->left);
            q.push(now->right);
        }
    }
    printf("\n%s", iscbt ? "YES" : "NO");
}
int main() {
    int n, temp;
    scanf("%d", &n);
    node *root = NULL;
    for (int i = 0; i < n; i++) {
        scanf("%d", &temp);
        insert(root, temp);
    }
    bfs(root, n);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值