1. 程式人生 > >根據前序遍歷判斷二叉搜尋樹

根據前序遍歷判斷二叉搜尋樹

題意:給你一個二叉樹的前序遍歷序列,讓你判斷是不是二叉搜尋樹(左子樹小於根,右子樹大於根)或其映象。如果是,輸出後序遍歷序列。

開始走了彎路,一直在思考如何建樹,結果試了很多種方法都不對,總是在一個新節點該放在哪個節點下出問題。

其實這道題可以和給出前序中序寫後序這種題類比,完全可以不建樹。根據前序遍歷的性質每次可以把根節點分離出來;根據二叉搜尋樹的性質每次可以把左右子樹分開;這樣在判斷的時候只判斷左邊的是不是都小於根,右邊的是不是都大於根就行了。至於後續序列,在遞迴左右之後,用b陣列儲存。

#include <stdio.h>
#include <algorithm>
using namespace std;
int a[1003], n, k = 0, b[1003]; 
int check1(int l, int r)
{
	if(l > r)
	    return 1;
	int root = a[l];//把根節點拿出來 
	int i, j;
	for(i = l + 1 ; i <= r && a[i] < root; i++);//根據二叉搜尋樹的性質,把左右子樹分開 
	for(j = i ; j <= r ; j++)//檢查右子樹是不是都大於根 
	{
		if(a[j] < root)
		    return 0;
	}
	if(check1(l + 1, i - 1) == 0)//遞迴地檢查左右子樹 
	    return 0;
	if(check1(i, r) == 0)
	    return 0;
	b[k++] = a[l];//b儲存後序遍歷序列 
	return 1;
}
int check2(int l, int r)
{
	if(l > r)
	    return 1;
	int root = a[l];
	int i, j;
	for(i = l + 1 ; i <= r && a[i] >= root; i++);
	for(j = i ; j <= r ; j++)
	{
		if(a[j] >= root)
		    return 0;
	}
	if(check2(l + 1, i - 1) == 0)
	    return 0;
	if(check2(i, r) == 0)
	    return 0;
	b[k++] = a[l];
	return 1;
}
int main()
{
	int i;
	scanf("%d", &n);
	for(i = 1 ; i <= n ; i++)
	    scanf("%d", &a[i]);
	if(n == 1)
	{
		printf("YES\n%d\n", a[1]);
		return 0;
	}
	if(a[1] > a[2])
	{
		if(check1(1, n))
		{
			printf("YES\n");
			for(i = 0 ; i < n - 1 ; i++)
			    printf("%d ", b[i]);
			printf("%d\n", b[n - 1]);
		}
		else
		    printf("NO\n");
	}
	else
	{
		if(check2(1, n))
		{
			printf("YES\n");
			for(i = 0 ; i < n - 1 ; i++)
			    printf("%d ", b[i]);
			printf("%d\n", b[n - 1]);
		}
		else
		    printf("NO\n");
	}
	return 0;
}