原文链接 http://blog.youkuaiyun.com/gzzheyi/article/details/8790267
题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回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