L2-004 这是二叉搜索树吗? (25 分)

原题链接icon-default.png?t=M276https://pintia.cn/problem-sets/994805046380707840/problems/994805070971912192

分析

本题主要考察了二叉搜索树(二叉排序树)的性质:

  1. 二叉排序树的左子树全部小于根节点,右子树全部大于等于根节点,同理,二叉排序树的每个非叶子结点都满足

    T:在判断所给序列是否是前序序列时就用这个性质判断,因为前序是先根再左再右,所以每个二叉排序树的前序遍历数组(1~n)都会满足:从第二个位置开始都比第一个位置(根节点)小,直到遇到第一个比根节点大的,后面都必须都比根节点大
  2. 二叉排序树的中序遍历就是所有结点的值从小到大的排列,即将前序遍历的结果按从小到大排序就是中序遍历

    T:利用这个性质,得到树的前中后序,就可以生成它的后序了

注意:对于镜像,大小判断的标准反过来就行,同时镜像的前序,左右子树的位置互换了,所以要从后面开始往前遍历。

因为本人写的代码太过繁琐,借鉴了网上的一篇思路非常清晰的代码,做了详细的注释供大家参考

代码

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

const int N = 1e3 + 5;
int pre[N], in[N], post[N], idx;
int n;

//判断是不是前序
bool isPre(int a[], int left, int right)
{
    //如果只有一个节点了自然是正确的返回true
    if (left >= right)
        return true;
    int i = left + 1, j;
    //从左往右遍历,二叉搜索树(二叉排序树)的左子树是小于根节点的
    while (i <= right && a[i] < a[left])
        i++;
    j = i; //得到左右子树的分界线
    //继续往后遍历,此时是根节点的右子树,都要大于等于根节点
    while (i <= right && a[i] >= a[left])
        i++;
    //如果i没要到right+1,说明至少有一个点是违背了二叉搜索树的规则导致提前退出循环,所以返回false
    if (i <= right)
        return false;

    //再去分别判断左右子树是否满足
    bool l = isPre(a, left + 1, j - 1);
    bool r = isPre(a, j, right);

    return l && r;
}

//判断是不是镜像
bool isMirror(int a[], int left, int right)
{
    if (left >= right)
        return true;
    int i = left + 1, j;

    while (i <= right && a[i] >= a[left])
        i++;
    j = i;
    while (i <= right && a[i] < a[left])
        i++;

    if (i <= right)
        return false;

    bool l = isMirror(a, left + 1, j - 1);
    bool r = isMirror(a, j, right);

    return l && r;
}

void getPost(int pre[], int in[], int len)
{
    if (len <= 0)
        return;
    int i;
    for (i = 0; i < len; i++)
        if (in[i] == pre[0])
            break;

    getPost(pre + 1, in, i);
    getPost(pre + i + 1, in + i + 1, len - i - 1);
    post[idx++] = pre[0];
}

void getPost_Mirror(int pre[], int in[], int len)
{
    if (len <= 0)
        return;
    int i;
    //镜像的前序,左右子树的位置互换了,所以要从后面开始往前遍历
    for (i = len - 1; i >= 0; i--)
        if (in[i] == pre[0])
            break;

    getPost(pre + 1, in, i);
    getPost(pre + i + 1, in + i + 1, len - i - 1);
    post[idx++] = pre[0];
}
bool cmp(int a, int b)
{
    return a > b;
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> pre[i];
        in[i] = pre[i];
    }

    if (isPre(pre, 1, n))
    {
        cout << "YES" << '\n';
        //对于二叉搜索树(二叉排序树)的中序遍历就是树的所有结点从小到大的排列
        //对前序序列进行排序得到的就是中序序列
        sort(in + 1, in + 1 + n);
        getPost(pre + 1, in + 1, n);
        cout << post[0];
        for (int i = 1; i < n; i++)
            cout << " " << post[i];
    }
    else if (isMirror(pre, 1, n))
    {
        cout << "YES" << '\n';
        sort(in + 1, in + 1 + n, cmp);
        getPost_Mirror(pre + 1, in + 1, n);
        cout << post[0];
        for (int i = 1; i < n; i++)
            cout << " " << post[i];
    }
    else
        cout << "NO";

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
根据引用的定义,二叉搜索树具有以下性质: 1. 任一节点的左子树中所有节点的键值小于该节点的键值; 2. 任一节点的右子树中所有节点的键值大于等于该节点的键值; 3. 任一节点的左右子树都是二叉搜索树。 根据引用的描述,我们可以通过递归来构造二叉搜索树。具体来说,对于一个序列,首先确定序列的起始点作为根节点,然后从起始点的下一个节点开始遍历,直到找到第一个比根节点大或等于的节点作为右子树的起始点,而左子树的节点则是在起始点和右子树起始点之间的节点。如果在遍历过程中存在比根节点小的节点,说明该序列不是二叉搜索树。 根据引用,如果输入序列是一棵二叉搜索树或其镜像进行前序遍历的结果,那么首先在一行中输出"YES",然后在下一行输出该树的后序遍历结果。如果输入序列不是二叉搜索树,则输出"NO"。 所以,对于问题L2-004这是二叉搜索树吗?C,我们可以使用上述方法来判断输入序列是否是一棵二叉搜索树。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [天梯赛L2-004 这是二叉搜索树吗? (25 )](https://blog.csdn.net/weixin_50026222/article/details/122836219)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [PTA L2-004 这是二叉搜索树吗?](https://blog.csdn.net/qq_51504747/article/details/127817010)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

linengcs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值