题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。
例如输入数组{5,7,6,9,11,10,8},则返回true,如果输入的数组是{7,4,6,5},则返回false。
我的思路:
由于之前看了那个重组二叉树的题目,所以很容易就想出类似的解法。
一个二叉搜索树的后序遍历结果中,序列的最后一个元素肯定是这棵树的根结点,而紧跟在前的是根结点的右子树。那么这些右子树的结点都会比根结点大,而根结点点左子树的值都比根结点小。这样的话,我就可以从根结点开始向后遍历,直到找到一个比根结点值要小的结点,这个结点就是左子树的最后一个结点。然后继续遍历,如果在遍历过程中没有找到比根结点大的结点的话,则证明符合后序遍历规则。如果继续遍历的过程中再次发现比根结点大的结点,则证明不符合后序遍历规则。(代码中显示了边界情况,则只有右子树或者左子树的情况)。
然后分别递归判断上面找到的左子树和右子树序列。
详见代码:
#include<cstdio>
#include<iostream>
const int N = 100 ;
bool IsPostOrder(int *PostOrder ,int nLength) ;
bool IsPostOrderCore(int *PostOrder ,int nLength) ;
int main(void)
{
int n ;
int PostOrderSeq[N] ;
freopen("in.txt","r",stdin) ;
while(scanf("%d",&n) != EOF)
{
int i ;
for(i = 0 ; i < n ; ++i)
{
scanf("%d",&PostOrderSeq[i]) ;
}
bool IsTrue = IsPostOrder(PostOrderSeq,n) ;
if(true == IsTrue)
{
printf("Yes\n") ;
}
else
{
printf("No\n") ;
}
}
return 0 ;
}
bool IsPostOrder(int *PostOrder ,int nLength)
{
if(NULL == PostOrder || 0 == nLength)
{
return false ;
}
return IsPostOrderCore(PostOrder,nLength) ;
}
bool IsPostOrderCore(int *PostOrder,int nLength)
{
if(NULL == PostOrder) //无效输入
{
return false ;
}
if(nLength <= 1) //当剩下一个元素的时候,证明后序遍历过程正确,递归过程结束
{
return true ;
}
int nRootValue = PostOrder[nLength-1] ; //根结点的根
int nRightLength = nLength ; //根结点右子树的值,默认根只有右子树,是一种边界情况
int *pPostEnd = PostOrder + nLength - 1 ; //后序遍历序列的末尾
int *pPostBeg = PostOrder ; //后序遍历序列的开始
int *pRightBeg = PostOrder ; //后序遍历中,根结点右子树的开始结点,默认根只有右子树,是一种边界情况
pPostEnd-- ;
while(pPostEnd >= pPostBeg) //从序列最后开始查找,找到左右子树的分界点
{
if(*pPostEnd < nRootValue && nLength == nRightLength) //找到分界点
{
nRightLength = pPostBeg + nLength - pPostEnd - 1 ;
pRightBeg = pPostEnd + 1 ;
}
else if(*pPostEnd > nRootValue && nRightLength != nLength) //出错情况,也就是不符合后序遍历的情况
{
return false ;
}
pPostEnd-- ;
}
int nLeftLength = nLength - nRightLength ; //左子树的结点数
return IsPostOrderCore(pPostBeg,nLeftLength) && IsPostOrderCore(pRightBeg,nRightLength-1) ; //递归地判断左右子树是否也是符合后序遍历
}
而书上的解法和我的基本一致:
在后序遍历得到的序列中,最后一个数字是树的根结点的值。数组中前面的数字可以分为两部分:第一部分是左子树结点的值,它们都比根结点的值小;第二部分是右子树的值,它们都比根结点的值大。
代码:
bool VerifySequenceOfBST(int sequence[], int length)
{
if(sequence == NULL || length <= 0)
{
return false ;
}
int root = sequence[length-1] ;
//在二叉搜索树中的左子树的结点小于根结点
int i = 0 ;
for(; i < length - 1 ; ++i)
{
if(sequence[i] > root)
{
break ;
}
}
//二叉搜索树中右子树的结点大于根结点
int j = i ;
for(; j < length - 1 ; ++j)
{
if(sequence[j] < root)
{
return false ;
}
}
//判断左子树是不是二叉搜索树
bool left = true ;
if(i > 0)
{
left = VerifySequenceOfBST(sequence,i) ;
}
//判断右子树是不是二叉搜索树
bool right = true ;
if(i < length - 1)
{
right = VerifySequenceOfBST(sequence + i, length - i - 1) ;
}
return (left && right) ;
}
测试数据:
7
7 8 9 17 16 10 18
4
10 9 8 7
7
5 7 6 9 11 10 8
4
7 4 6 5
5
8 6 12 11 10
4
7 8 9 10
1
10
2
9 10
2
10 9
10
7 6 8 4 15 14 16 12 20 10