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

题目链接是

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值