算法—判断整数序列是不是二元查找树的后序遍历结果

BST性质:节点左子树的任意节点小于根节点,右子树的任意节点大于等于根节点


后序遍历顺序:左——右——根

这个顺序很重要。由这个可以得知。对于任何一棵BST来说,后续遍历序列的最后一个数就是根节点。除此之外,左子树的所有节点在序列的前部,右子树的所有节点在序列的右部。注意到了这个,问题就没那么复杂了


来分析这个后序序列:5,7,6,9,11,10,8

假设它是个BST的后续遍历序列。那8就是这棵BST的根节点。左子树节点为:5,7,6。右子树节点为:9,11,10。

进一步分析左子树和右子树。

对于左子树:5,7,6。根节点为6,左子树为5。右子树为7。

对于右子树:9,11,10。根节点为10,左子树为9,右子树为11。

因此这个BST为:

                            8

                        ↙   ↘

                      6         10

                 ↙   ↘   ↙   ↘

               5         7  9        11


再来考虑后序序列:7,4,6,5。

同样假设它是一棵BST。那么5就是根节点。由于左子树节点都比根节点的小,且分布在序列前部。但是序列第一个节点为7,所以如果BST成立,则这棵BST的根节点没有左子树。因此右子树节点就是7,4,6。但是,由于右节点都大于或等于根节点。7,4,6明显不满足。因此这个序列不可能构成一棵BST。


总结一下。其实算法的思路就是:

1. 从初始序列开始,通过最后一个节点(根节点)将序列分割为左子树部分和右子树部分。

2. 判断左子树部分的所有节点是否都小于根节点,判断右子树的所有节点是否都大于或等于根节点。

3. 如果2成立,则对左右子树进行递归(和快排很像)。否则算法停止。

4. 如果递归到叶子节点,算法都未停止则返回true。表示这个序列是某一BST的后序遍历序列。


代码如下:

#include <iostream>
using namespace std;

template <class T>
bool isBST(T *array,int size);

template <class T>
int rightPartPos(T *array,int size);

int main()
{
	int array1[7]={5,7,6,9,11,10,8};
	cout<<isBST(array1,8)<<endl;
	int array2[4]={7,4,6,5};
	cout<<isBST(array2,4)<<endl;
	return 0;
}

template <class T>
bool isBST(T *array,int size)
{
	//递归到根节点
	if(size<=1)
	{
		return true;
	}
	//没有递归到根节点
	else
	{
		//分割左右子树,返回值为右子树部分开始的位置
		int pos=rightPartPos(array,size);
		//右子树部分的节点中存在小于根节点的节点
		if(pos<0)
		{
			return false;
		}
		else
		{
			//遍历,检查左、右子树
			return isBST(array,pos)&&isBST(array+pos,size-pos-1);
		}
	}	
}

template <class T>
int rightPartPos(T *array,int size)
{
	T root=*(array+size-1);
	for(int i=0;i<size-1;i++)
	{
		//当遇到小于根节点的节点继续往后找
		if(root>*(array+i))
		{
			continue;
		}
		//第一个大于或等于根节点的节点
		//此时i位置的节点就是右子树部分的第一个节点
		else
		{
			//判断右子树部分的节点是否大于或等于根节点
			for(int j=i+1;j<size-1;j++)
			{
				//右子树部分节点中存在小于根节点的节点。BST不成立
				if(*(array+j)<root)
				{
					return -1;
				}
			}
			return i;	//返回右子树开始的位置
		}
	}
	return size-1;	//表示没有右子树
}

如果是给出前序遍历的序列,其实就是根节点在最前面。算法的其他部分还是一样。至于给出中序遍历的序列,只要是递增的就行了~


如果有什么不对的地方欢迎指出。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值