【PAT甲级 - C++题解】1123 Is It a Complete AVL Tree

简介: 【PAT甲级 - C++题解】1123 Is It a Complete AVL Tree

1123 Is It a Complete AVL Tree


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.

f05219373a994db4a8a891199424eee9.jpg


eff9678edc604e5296603766d9e2dec4.jpg



d777540bf70a472b80c39d71e2440b60.jpg


c45eee7176d34f8ab0fbcab265327994.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
• 1
• 2

Sample Output 1:

70 63 88 61 65
YES



Sample Input 2:

8
88 70 61 96 120 90 65 68
• 1
• 2

Sample Output 2:

88 65 96 61 70 90 120 68
NO


题意

AVL 树是一种自平衡二叉搜索树。


在 AVL 树中,任何节点的两个子树的高度最多相差 1 个。


如果某个时间,某节点的两个子树之间的高度差超过 1 ,则将通过树旋转进行重新平衡以恢复此属性。


现在,给定插入序列,请你输出得到的 AVL 树的层序遍历,并判断它是否是完全二叉树。

思路

这道题其实就是对平衡二叉树的构建和判断是否为完全二叉树的结合,我们分两部分进行讲解。


首先,平衡二叉树失衡主要分为四种情况,下面讨论的是导致失衡前最后插入的一个结点位置:


插入的结点在失衡结点的左孩子的左子树,直接右旋失衡结点。

插入的结点在失衡结点的左孩子的右子树,先对失衡结点的左孩子进行左旋,再对失衡结点右旋。

插入的结点在失衡结点的右孩子的右子树,直接左旋失衡结点。

插入的结点在失衡结点的右孩子的左子树,先对失衡结点的右孩子进行右旋,再对失衡结点左旋。

其次,再来看看该如何判断是否为完全二叉树:


我们可以利用完全二叉树的性质,用一个一维数组来存储,如果当前结点第下标为 k (假设下标从 1 开始),则满足以下条件:

该结点的左孩子下标为 k * 2

该结点的右孩子下标为 k * 2 + 1

所以如果一个二叉树是完全二叉树的话,将它所有结点按上述方式存储到一维数组中是可以刚好填满 1 ∼ N 1\sim N1∼N(下标从 1 11 开始)个位置的。相反如果不是完全二叉树,则 1 ∼ N 1\sim N1∼N 个位置中会有空余,也就是说最后一个结点的位置会大于 N NN 。故我们只用判断最后一个结点的位置是否为 N NN 即可,如果是 N NN 则说明是完全二叉树。

最后输出判断结果,注意如果是完全二叉树还需要输出最后一个结点的编号,否则输出该树的根结点编号。

我们拿题目的第一个样例举例,可以得到下面这颗完全二叉树:



2998733604cd4be6b305fb42ef96bfa5.png


其在一维数组中的存储情况为:

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 25;
int n;
int l[N], r[N], h[N], v[N], idx;
int q[N], pos[N];
//更新当前结点的深度
void update(int u)
{
    h[u] = max(h[l[u]], h[r[u]]) + 1;
}
//右旋
void R(int& u)
{
    int p = l[u];
    l[u] = r[p], r[p] = u;
    update(u), update(p);
    u = p;
}
//左旋
void L(int& u)
{
    int p = r[u];
    r[u] = l[p], l[p] = u;
    update(u), update(p);
    u = p;
}
//获取左右结点深度之差
int get_balance(int u)
{
    return h[l[u]] - h[r[u]];
}
//插入结点
void insert(int& u, int w)
{
    if (!u)  u = ++idx, v[u] = w;
    else if (w < v[u])
    {
        insert(l[u], w);
        if (get_balance(u) == 2)
        {
            //如果插入结点在失衡结点的左孩子的左子树,则对失衡结点右旋
            if (get_balance(l[u]) == 1)   R(u);
            //如果插入结点在失衡结点的左孩子的右子树,则先对左孩子左旋,再对失衡结点右旋
            else    L(l[u]), R(u);
        }
    }
    else
    {
        insert(r[u], w);
        if (get_balance(u) == -2)
        {
            //如果插入结点在失衡结点的右孩子的右子树,则对失衡结点左旋
            if (get_balance(r[u]) == -1)   L(u);
            //如果插入结点在失衡结点的右孩子的左子树,则先对右孩子右旋,再对失衡结点左旋
            else    R(r[u]), L(u);
        }
    }
    update(u);  //更新当前结点的深度
}
//判断是否是完全二叉树
bool bfs(int root)
{
    int hh = 0, tt = 0;
    q[0] = root;
    pos[root] = 1;
    bool res = true;
    while (hh <= tt)
    {
        int t = q[hh++];
        if (pos[t] > n)    res = false;
        if (l[t])   q[++tt] = l[t], pos[l[t]] = pos[t] * 2;
        if (r[t])   q[++tt] = r[t], pos[r[t]] = pos[t] * 2 + 1;
    }
    return res;
}
int main()
{
    cin >> n;
    int root = 0;
    for (int i = 0; i < n; i++)
    {
        int w;
        cin >> w;
        insert(root, w);
    }
    bool res = bfs(root);
    cout << v[q[0]];
    for (int i = 1; i < n; i++)    cout << " " << v[q[i]];
    cout << endl;
    if (res)    puts("YES");
    else    puts("NO");
    return 0;
}


目录
相关文章
|
6月前
|
C++
【数据结构】—AVL树(C++实现)
【数据结构】—AVL树(C++实现)
|
4月前
|
编译器 开发工具 C++
【Python】已解决error: Microsoft Visual C++ 14.0 or greater is required. Get it with “Microsoft C++ Build
【Python】已解决error: Microsoft Visual C++ 14.0 or greater is required. Get it with “Microsoft C++ Build
2076 0
|
6月前
|
算法 测试技术 C++
【C++】map&set的底层结构 -- AVL树(高度平衡二叉搜索树)(下)
【C++】map&set的底层结构 -- AVL树(高度平衡二叉搜索树)(下)
|
6月前
|
C++ 容器
【C++】map&set的底层结构 -- AVL树(高度平衡二叉搜索树)(上)
【C++】map&set的底层结构 -- AVL树(高度平衡二叉搜索树)(上)
|
2月前
|
存储 C++
【C++】AVL树
AVL树是一种自平衡二叉搜索树:它以苏联科学家Georgy Adelson-Velsky和Evgenii Landis的名字命名。
27 2
|
6月前
|
存储 C++ 容器
c++的学习之路:26、AVL树
c++的学习之路:26、AVL树
50 0
|
3月前
|
C++ 容器
【C++航海王:追寻罗杰的编程之路】关联式容器的底层结构——AVL树
【C++航海王:追寻罗杰的编程之路】关联式容器的底层结构——AVL树
34 5
|
4月前
|
C++
【C++】手撕AVL树(下)
【C++】手撕AVL树(下)
51 1
|
4月前
|
算法 测试技术 C++
【C++高阶】掌握AVL树:构建与维护平衡二叉搜索树的艺术
【C++高阶】掌握AVL树:构建与维护平衡二叉搜索树的艺术
35 2
|
4月前
|
Java C++ Python
【C++】手撕AVL树(上)
【C++】手撕AVL树(上)
52 0