判断一个序列是否是二叉查找树的后序、前序、中序遍历序列

本文参考:http://zhedahht.blog.163.com/blog/static/25411174200725319627/

题目:输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。如果是返回true,否则返回false

例如输入576911108,由于这一整数序列是如下树的后序遍历结果:

      8
       /  \
      6    10
    / \    / \
   5   7   9  11

因此返回true

在后续遍历得到的序列中,最后一个元素为树的根结点。从头开始扫描这个序列,比根结点小的元素都应该位于序列的左半部分;从第一个大于根结点开始到根结点前面的一个元素为止,所有元素都应该大于根结点,因为这部分元素对应的是树的右子树。根据这样的划分,把序列划分为左右两部分,我们递归地确认序列的左、右两部分是不是都是二元查找树。

就拿上面那个序列{576911108}为例,后序遍历结果的最后一个数字8就是根节点的值。在这个数组中,前3个数字5、7和6都比8小,是值为8的节点的左子树节点;后3个数字9,11,10都比8大,是值为8的节点的右子树节点。 我们接下来用同样的方法确定与数组每一部分对应的子树的结构。这其实就是一个递归的过程。对于序列5,7,6,最后一个数字6是左子树的根节点的值。数字5比6小,是值为6的节点的左子结点,而7则是它的右子节点。同样,在序列9,11,10中,最后一个数字10是右子树的根节点,数字9比10小,是值为10的节点的左子结点,而11则是它的右子结点。

我们再来分析另一个序列{7,4,6,5}。后序遍历的最后一个数是根节点,因此根节点的值是5.由于第一个数字7大于5,因此在对应的二叉搜索树中,根节点上是没有左子树的,数字7,4,6都是右子树节点的值。但我们发现在右子树中有一个节点的值是4,比根节点的值5小,这违背了二叉搜索树的定义。因此不存在一颗儿茶搜索树,它的后续遍历的结果是7,4,6,5。

明白规律后,代码如下:

#include <iostream>
using namespace std;

bool invaluedInput = false;

//检查序列sequence是否是二叉查找树的后序遍历序列,start与end分别是序列的开始与结束位置
bool CheckSequenceOfLRDOfBST(int sequence[],int start,int end)
{
	if(NULL == sequence || start > end)
	{
		invaluedInput = true;
		return false;
	}

	//只有一个节点时,返回true
	if(start == end)
		return true;

	//根节点为序列的最后一个值
	int root = sequence[end];
	int bound = start;
	/*bound为序列的左子树与右子树的分界点,左子树的值都小于根节点的值,bound指向序列中第一个大于root的值,
	即右子树的开始节点,bound--en-1为右子树序列*/
	for(bound; bound<end; bound++)
	{
		if(sequence[bound] > root)
			break;
	}
	
	int i = bound;
	//在右子树的序列中如果查找到一个节点值小于根节点的值,则不符合二叉查找树的定义,返回false
	for(i; i<end; i++)
	{
		if(sequence[i] < root)
			return false;
	}

	bool left = true;
	bool right = true;
	//递归判断序列左半边是不是二叉查找树的后续序列,如果bound==start则这颗二叉查找树无左子树
	if(bound>start)
		left = CheckSequenceOfLRDOfBST(sequence,start,bound-1);
	//递归判断序列右半边是不是二叉查找树的后续序列,如果bound==end则这颗二叉查找树无右子树
	if(bound<end)
		right = CheckSequenceOfLRDOfBST(sequence,bound,end-1);
	return left && right;
}

int main()
{
	//int sequence[] = {5,9,8,11,13,12,10};
	//int sequence[] = {8,7,6,5};
	//int sequence[] = {5,6,7,8};
	//int sequence[] = {7,8};
	//int sequence[] = {8,7};
	int sequence[] = {8};
	int len = sizeof(sequence)/sizeof(int);
	bool result = CheckSequenceOfLRDOfBST(sequence,0,len-1);
	if(result)
		cout<<"YES"<<endl;
	else
		cout<<"NO"<<endl;
	return 0;
}


题目:输入一个整数数组,判断该数组是不是某二元查找树的前序遍历的结果。如果是返回true,否则返回false

同理可得: 在前续遍历得到的序列中,第一个元素为树的根结点。从第二个节点开始扫描这个序列,比根结点小的元素都应该位于序列的左半部分;从第一个大于根结点开始到最后一个元素为止,所有元素都应该大于跟结点,因为这部分元素对应的是树的右子树。根据这样的划分,把序列划分为左右两部分,我们递归地确认序列的左、右两部分是不是都是二元查找树。

代码如下:

#include <iostream>
using namespace std;

bool invaluedInput = false;

//检查序列sequence是否是二叉查找树的前序遍历序列,start与end分别是序列的开始与结束位置
bool CheckSequenceOfDLROfBST(int sequence[],int start,int end)
{
	if(NULL == sequence || start > end)
	{
		invaluedInput = true;
		return false;
	}

	//只有一个节点时,返回true
	if(start == end)
		return true;

	//根节点为序列的第一个值
	int root = sequence[start];
	int bound = start+1;
	/*bound为序列的左子树与右子树的分界点,左子树的值都小于根节点的值,bound指向序列中第一个大于root的值,
	即右子树的开始节点,bound~~~~en-1为右子树序列*/
	for(bound; bound<=end; bound++)
	{
		if(sequence[bound] > root)
			break;
	}
	
	int i = bound;
	//在右子树的序列中如果查找到一个节点值小于根节点的值,则不符合二叉查找树的定义,返回false
	for(i; i<=end; i++)
	{
		if(sequence[i] < root)
			return false;
	}

	bool left = true;
	bool right = true;
	//递归判断序列左半边是不是二叉查找树的后续序列,如果bound==(start+1)则这颗二叉查找树无左子树
	if(bound>(start+1))
		left = CheckSequenceOfDLROfBST(sequence,start+1,bound-1);
	//递归判断序列右半边是不是二叉查找树的后续序列,如果bound==(end+1)则这颗二叉查找树无右子树
	if(bound<=end)
		right = CheckSequenceOfDLROfBST(sequence,bound,end);
	return left && right;
}

int main()
{
	//测试用例
	//int sequence[] = {10,8,5,9,12,11,13};
	//int sequence[] = {9,7,6,8,10};
	//int sequence[] = {6,5,9,7,10};
	//int sequence[] = {8,7};
	//int sequence[] = {8,9};
	int sequence[] = {8};
	int len = sizeof(sequence)/sizeof(int);
	bool result = CheckSequenceOfDLROfBST(sequence,0,len-1);
	if(result)
		cout<<"YES"<<endl;
	else
		cout<<"NO"<<endl;
	return 0;
}

题目:输入一个整数数组,判断该数组是不是某二元查找树的中序遍历的结果。如果是返回true,否则返回false

分析:一颗二叉查找树的中序遍历序列应该是一个按升序排列的序列,我们只要判断这个序列是否是按升序排列即可判断序列是否是二叉搜索树的中序遍历序列。为了提高效率,我用了分治的方法,将序列从中间分为两部分,记中间值为midValue。左边部分的值都小于midValue,右边部分的值都大于midValue。然后再递归的判断左边序列和右边序列,只有当左边序列和右边序列都符合条件是递增的时,整个序列才是递增的。
下面是我的代码:
#include <iostream>
using namespace std;

bool invaluedInput = false;

bool IsSequenceAsc(int sequence[],int start,int end)
{
	if(NULL == sequence || start > end)
	{
		invaluedInput = true;
		return false;
	}
	//当只有一个元素时,认为它有序。
	if(start == end)
		return true;

	//防止溢出,相当于是mid=(end+start)/2
	int mid = end - ((end-start)>>1);
	int midValue = sequence[mid];
	int i,j;
	//左边的序列都小于midValue,否则返回false
	for(i=0; i<mid; i++)
	{
		//如果数组中有重复元素,则条件变为:sequence[i] >= midValue即可
		if(sequence[i] > midValue)
			return false;
	}
	//右边的序列都大于midValue,否则返回false,如果数组中有重复元素,则条件变为:sequence[j] <= midValue即可
	for(j=mid+1; j<=end; j++)
		if(sequence[j] < midValue)
			return false;

	int left = true;
	int right = true;
	if(mid > start)
		left = IsSequenceAsc(sequence,start,mid-1);
	if(mid < end)
		right = IsSequenceAsc(sequence,mid+1,end);
	return left&&right;
}

int main()
{
	//测试用例
	//int sequence[] = {1,2,3,4,5,6,7,8,9};
	//int sequence[] = {8,7};
	//int sequence[] = {8,9};
	//int sequence[] = {1,2,8,4,5,6,7,4,9};
	//int sequence[] = {1,2,3,4,5,6,7,9,8};
	//int sequence[] = {2,1,3,4,5,6,7,8,9};
	int sequence[] = {8};
	int len = sizeof(sequence)/sizeof(int);
	bool result = IsSequenceAsc(sequence,0,len-1);
	if(result)
		cout<<"YES"<<endl;
	else
		cout<<"NO"<<endl;
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值