pat1043Is It a Binary Search Tree (25)

本文详细解释了如何通过递归方法判断给定序列是否为二叉查找树或其镜像的先序遍历序列,并提供了构造后序序列的方法,同时注意区分BST与镜像BST的区别。

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

题意分析:

(1)给出一数列,判断这个数列是否是一个二叉查找树的先序遍历序列或镜像二叉查找树的先序遍历序列,所谓镜像二叉查找树就是二叉查找树所有节点的左右子树交换后的二叉树

(2)二叉查找树有一个特性就是根节点左边所有子树节点的值小于根节点的值,右子树所有节点的值大于或等于根节点的值,同时左右子树也是一颗二叉查找树

(3)由(2)的递归的性质:于是判断这个序列是否是BST或者镜像BST先序遍历序列也是递归实现的:若是BST,首先根节点i肯定是第一个数,假设之后从i+1到j的连续项是小于num[i]的,按照定义,这是左子树,从第j+1项起,后面所有项是右子树,若存在小于num[i]的项,则这一定不是BST的先序遍历序列。然后递归判断下去。

(4)接下来就是要根据有规律的先序序列来构造后序序列,策略依然是递归构造。这里有两种思路:一种是根据这种BST性质和先序序列去构造二叉树,然后再后序遍历这颗二叉树。但是很遗憾,这样做会导致段错误,是因为数据量过大时建树会造成溢出,代码如下:

void buildTree(TreeNode *&root,int num[],int start,int end,bool flag)
{
    root=(TreeNode*)malloc(sizeof(TreeNode));
    if(start==end)
    {
        root->value=num[start];
        root->lchild=NULL;
        root->rchild=NULL;
        return;
    }
    if(start>end)root=NULL;
    int lr,rl;
    if(flag)
    {
        for(lr=start+1;lr<=end&&num[lr]<num[start];lr++);
        for(rl=lr;rl<=end;rl++)
        {
            if(num[rl]<num[start])return;
        }
    }
    else
    {
        for(lr=start+1;lr<=end&&num[lr]>=num[start];lr++);
        for(rl=lr;rl<=end;rl++)
        {
            if(num[rl]>=num[start])return;
        }
    }
    root->value=num[start];
    buildTree(root->lchild,num,start+1,lr-1,flag);
    buildTree(root->rchild,num,lr,end,flag);
}
另外一种思路就是直接使用递归打印:因为左右子树的边界很容易确定,因此先访问左子树,再访问右子树,再访问根节点。

(5)最后需要注意的是:要区分是BST还是镜像BST,很简单,直接判断num[0]和num[1]的大小,然后设置flag来标识这是按什么顺序来作为参数传入,这样就避免相同代码的冗余

可能坑点:

(1)不要建树,否则会因为存储过大导致段错误

(2)要区分BST和镜像BST

#include <iostream>
#include <stdlib.h>
using namespace std;
int num[1001];
bool checkBST(int num[],int start,int end,bool flag)
{
    if(start>=end)return true;
    int lr,rl;
    if(flag)
    {
        for(lr=start+1;lr<=end&&num[lr]<num[start];lr++);
        for(rl=lr;rl<=end;rl++)
        {
            if(num[rl]<num[start])return false;
        }
    }
    else
    {
        for(lr=start+1;lr<=end&&num[lr]>=num[start];lr++);
        for(rl=lr;rl<=end;rl++)
        {
            if(num[rl]>=num[start])return false;
        }
    }
    if(checkBST(num,start+1,lr-1,flag)&&checkBST(num,lr,end,flag))
    {
        return true;
    }
}
int first=1;
void postOrder(int num[],int start,int end,bool flag)
{
    if(start>end)return;
    int lr,rl;
    if(flag)
    {
        for(lr=start+1;lr<=end&&num[lr]<num[start];lr++);
        for(rl=lr;rl<=end;rl++)
        {
            if(num[rl]<num[start])return;
        }
    }
    else
    {
        for(lr=start+1;lr<=end&&num[lr]>=num[start];lr++);
        for(rl=lr;rl<=end;rl++)
        {
            if(num[rl]>=num[start])return;
        }
    }
    postOrder(num,start+1,lr-1,flag);
    postOrder(num,lr,end,flag);
    if(first)first=0;
    else cout<<" ";
    cout<<num[start];
}
int main()
{
    int N,i=0;
    cin>>N;
    while(i<N)cin>>num[i++];
    bool flag=(num[1]<num[0]?1:0);
    if(checkBST(num,0,N-1,flag))
    {
        cout<<"YES"<<endl;
        postOrder(num,0,N-1,flag);
    }
    else cout<<"NO"<<endl;
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值