天梯赛练习_L2-004_这是二叉搜索树吗?

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

问题描述

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

  • 其左子树中所有结点的键值小于该结点的键值;
  • 其右子树中所有结点的键值大于等于该结点的键值;
  • 其左右子树都是二叉搜索树。

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

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

输入

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

输出格式

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

分析

  • 根据前序遍历的特点, 对于某一结点而言, 先输出当前结点的键值, 再前序遍历输出左子树的键值, 最后前序遍历右子树的键值.
  • 假设我们得到了当前结点的前序遍历序列a[root], a[root+1], a[root+2], ... , a[tail]. 根据二叉搜索树的性质, 我们可以知道:
    1. a[root+1] -> a[tail]中, 第一个大于等于a[0]的 (假设其为a[i]), 一定是a[0]的右孩子
    2. a[tail] -> a[root+1]中, 第一个小于a[0]的 (假设其为a[j]), 一定是a[0]的左子树中的最后一个结点, 即输出a[j]后, 紧接着就要输出a[i]
  • 由此我们可以知道, 假如当前序列为二叉搜索树的前序遍历序列, 则对每一个结点, 一定满足i-j == 1
  • 我们还可以知道, a[root+1], ... , a[j] 为当前结点左子树的前序序列, a[i], ... , a[tail]为当前结点的右子树的前序序列.

代码实现

#include
#include
using namespace std;

int n;
int pre[1005];
bool flag=0;
vector<int>post;

void judge(int root, int tail){
	if(root>tail) return;
	int i=root+1,j=tail;
	if(!flag){
		while(i<=tail&&pre[i]<pre[root]) i++;
		while(j>root&&pre[j]>=pre[root]) j--;
	} 
	else{
		while(i<=tail&&pre[i]>=pre[root]) i++;
		while(j>root&&pre[j]<pre[root]) j--;	
	}
	if(i-j != 1) return;
	judge(root+1,j);
	judge(i,tail);
	post.push_back(pre[root]);
}

int main(){
	cin>>n;
	for(int i=0;i<n;i++) cin>>pre[i];
	judge(0,n-1);
	if(post.size()==n){
		cout<<"YES\n";
		cout<<post[0];
		for(int i=1;i<n;i++) cout<<" "<<post[i];
		return 0;
	}
	flag=1;
	post.clear();
	judge(0,n-1);
	if(post.size()==n){
		cout<<"YES\n";
		cout<<post[0];
		for(int i=1;i<n;i++) cout<<" "<<post[i];
		return 0;
	}
	else{
		cout<<"NO";
		return 0;
	}
}

参考资料

  • https://www.cnblogs.com/shengge-777/p/10398938.html

你可能感兴趣的:(数据结构)