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

9 篇文章 0 订阅
6 篇文章 0 订阅

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

  • 一棵二叉搜索树可被递归地定义为具有下列性质的二叉树:对于任一结点,

    • 其左子树中所有结点的键值小于该结点的键值;

    • 其右子树中所有结点的键值大于等于该结点的键值;

    • 其左右子树都是二叉搜索树。

    所谓二叉搜索树的“镜像”,即将所有结点的左右子树对换位置后所得到的树。

    给定一个整数键值序列,现请你编写程序,判断这是否是对一棵二叉搜索树或其镜像进行前序遍历的结果。

  • 输入格式

    输入的第一行给出正整数 N(≤1000)。随后一行给出 N 个整数键值,其间以空格分隔。

  • 输出格式

    如果输入序列是对一棵二叉搜索树或其镜像进行前序遍历的结果,则首先在一行中输出 YES ,然后在下一行输出该树后序遍历的结果。数字间有 1 个空格,一行的首尾不得有多余空格。若答案是否,则输出 NO

  • 输入样例1

    7
    8 6 5 7 10 8 11
    
  • 输出样例1

    YES
    5 7 6 8 11 10 8
    
  • 输入样例2

    7
    8 10 11 8 6 7 5
    
  • 输出样例2

    YES
    11 8 10 7 5 6 8
    
  • 输入样例3

    7
    8 6 8 5 10 9 11
    
  • 输出样例3

    NO
    
  • 解题思路:

    根据二叉搜索树的特性用递归来构造树,我们先看正常的树(没有镜像的树),首先对于一个序列,包括后面递归传进去的序列,该序列的起始点A肯定是该子树的根结点,在从这个起始点A(根结点)的下一个结点B开始遍历,遍历到该子树的结尾,找到第一个比该根结点大或者等于的点C,这个点C包括他后面的就是右子树,前面的不包括C和A就是该根结点的左子树。切记,找到之后,break出来,继续验证一下后面的结点是否再出现比根结点小的情况,若出现了,说明该子树压根就不是二叉搜索数,此时可以用一个全局标记来标记这个情况;若没有发现则就进行下一轮的递归。

    对于镜像的树,不需要把他翻转回去,直接输出这个镜像树的后序遍历结果就好。

在这里插入图片描述

  • 代码

    #include <iostream>
    using namespace std;
    
    int A[1010];
    // 判断是不是二叉搜索树(正常+镜像)
    int flag = 0;
    // count 为了在最后输出后序遍历时,不输出最后一个空格。
    int count = 0;
    int N;
    typedef struct TNode
    {
        int data;
        TNode *lchild, *rchild;
    } TNode, *Tree;
    
    int main()
    {
        Tree CreateABinarySearchTree(int l, int r, int len);
        Tree CreateABinarySearchTreeReverse(int l, int r, int len);
        void Traverse(TNode * T);
    
        cin >> N;
        int i;
        for (i = 1; i <= N; i++)
        {
            cin >> A[i];
        }
        TNode *T1 = CreateABinarySearchTree(1, N, N);
        // 正常的树不满足二叉搜索树的性质
        if(flag==-1)
        {
            // 镜像树也不符合镜像二叉树搜索数的性质
            TNode *T2 = CreateABinarySearchTreeReverse(1, N, N);
            if(flag==1)
            {
                cout << "NO" << endl;
            }
            // 符合镜像
            else
            {
                // cout << "zhelima" << endl;
                
                cout << "YES" << endl;
                Traverse(T2);
            }
        }
        // 符合正常
        else if(flag == 0)
        {
            cout << "YES" << endl;
            Traverse(T1);
        }
        
        return 0;
    }
    
    // 正常的二叉搜索数进行判断。
    Tree CreateABinarySearchTree(int l, int r, int len)
    {
        // cout << "递归了几次?" << endl;
        if (len <= 0 || flag == -1)
        {
            return NULL;
        }
        TNode *T = new TNode;
        int root = A[l];
        T->data = root;
        int i;
        int find = 0;
        int mid = l+1;
        int newLen = 0;
    
        // 找到第一个比他大或者等于的结点。
        /*
            要是找不到比他大的怎么办?可以分成两种情况进行讨论。
            1. 传进来的len > 1,但就是没有任何数字大于等于根结点,此时就没有右子树了,全部都是左子树,只要将mid=r+1即可
            2. 传进来的len = 1,此时循环根本执行不了,直接下一次递归返回NULL,这个结点就是个叶子结点,此时mid=r+1,l=r,newLen=0;
        */
        for (i = l + 1; i < len + l; i++)
        {
            if (A[i] >= root)
            {
                mid = i;
                find = 1;
                newLen = mid - l - 1;
                break;
            }
        }
        if(find==1)
        {
            for (i = mid + 1; i < len + l; i++)
            {
                if (A[i] < root)
                {
                    flag = -1;
                    return NULL;
                }
            }
        }
        else
        {
            mid = r + 1;
            newLen = mid - l - 1;
        }
       
            
        
    
        T->lchild = CreateABinarySearchTree(l + 1, mid - 1, newLen);
        T->rchild = CreateABinarySearchTree(mid, r, len - newLen - 1);
        return T;
    }
    
    // 镜像的处理
    Tree CreateABinarySearchTreeReverse(int l, int r, int len)
    {
        if (len <= 0 || flag == 1)
        {
            return NULL;
        }
        TNode *T = new TNode;
        int root = A[l];
        T->data = root;
        int i;
        int find = 0;
        int mid = 0;
        int newLen = 0;
        for (i = l + 1; i < len + l; i++)
        {
            if (A[i] < root)
            {
                mid = i;
                newLen = mid - l - 1;
                find = 1;
                break;
            }
        }
        
        if(find==1)
        {
            for (i = mid + 1; i < len + l; i++)
            {
                if (A[i] >= root)
                {
                    flag = 1;
                    return NULL;
                }
            }
        }
        else
        {
            mid = r + 1;
            newLen = mid - l - 1;
        }
            
        
    
        T->lchild = CreateABinarySearchTreeReverse(l + 1, mid - 1, newLen);
        T->rchild = CreateABinarySearchTreeReverse(mid, r, len - newLen - 1);
        return T;
    }
    
    void Traverse(TNode *T)
    {
        if (T == NULL)
        {
            
        }
        else
        {
            
            Traverse(T->lchild);
            Traverse(T->rchild);
            cout << T->data;
            count++;
            if(count<N)
            {
                cout << " ";
            }
        }
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值