L2-004. 这是二叉搜索树吗?

本文介绍了一种判断给定序列是否能构成二叉搜索树的方法,并通过递归方式构建该树,最后输出后序遍历序列。适用于算法学习与数据结构理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接是

https://www.patest.cn/contests/gplt/L2-004


题解:

根节点的值是位于左右子树之间的,即大于左子树的所有值,但是小于等于右子树的所有值。

而先序遍历的序列,第一个值就是其根的值,我们可以利用这些性质来递归判断一棵树是否为二叉搜索树。 

首先,遍历这个序列,找到第一个大于等于根节点值的节点,如果从这个节点开始之后的所有节点的值都是大于等于根节点的,那么这

棵树就是二叉搜索树。而二叉搜索树的“镜像”也可以利用这种思想进行判断。

 如果是一棵二叉搜索树或者是其镜像,我们就可以开始建树,建树之后可以递归的输出其后序遍历序列。


代码及注释:

#include <iostream>
#include <cstdio>
#include <vector>

using namespace std;

const int maxn = 1000+10;

struct Node
{
    int value;
    Node *lson, *rson;
    Node():lson(NULL),rson(NULL){}
}*root;

int n;
int s[maxn];
vector<int> ans; //按序记录后序遍历的元素,因为在后序遍历输出时不能控制最后的空格

//判断 kind为true判断原树,为false判断镜像
bool test(bool kind, int L, int R)
{
    if(L >= R)
        return true;
    int i;
    for(i = L+1; i <= R; i++)
    {
        if(kind)
        {
            if(s[L] <= s[i])
                break;      //到 i-1 为止为左子树
        }
        else
        {
            if(s[L] > s[i])
                break;
        }
    }
    bool flag = true;
    for(int j = i; j <= R; j++)
    {
        if(kind)
        {
            if(s[j] < s[L])
                flag = false;  //若右子树有小于根结点值的直接返回 false
        }
        else
        {
            if(s[j] >= s[L])
                flag = false;
        }

    }
    if(flag)
        return test(kind, L+1, i-1) && test(kind, i, R); //一直递归分治下去

    else
        return false;
}


Node* create(bool kind, int L, int R)
{
    if(L > R)
        return NULL;
    int i;
    for(i = L+1; i <= R; i++)
    {
        if(kind)
        {
            if(s[L] <= s[i])
                break;   //到i-1为止为左子树
        }
        else
        {
            if(s[L] > s[i])
                break;
        }
    }
    Node *p = new Node();
    p->value = s[L];
    p->lson = create(kind, L+1, i-1); //递归建立左子树
    p->rson = create(kind, i, R);  //递归建立右子树

    return p;
}

void postOrderTraverse(Node *p)
{
    if(p)
    {
        postOrderTraverse(p->lson);
        postOrderTraverse(p->rson);
        ans.push_back(p->value);
    }
}

void Print()
{
    postOrderTraverse(root);
    int len = ans.size();
    for(int i = 0; i < len-1; i++)
        printf("%d ", ans[i]);
    printf("%d\n", ans[len-1]);
}
int main()
{
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
        scanf("%d", &s[i]);

    int flag = 0;
    if(test(true, 0, n-1))
    {
        flag = 1;
        root = create(true, 0, n-1);
    }
    else if(test(false, 0, n-1))
    {
        flag = 2;
        root = create(false, 0, n-1);
    }
    if(flag != 0)
    {
        puts("YES");
        Print();
    }
    else
        puts("NO");

    return 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
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值