1. 程式人生 > 其它 >劍指offer程式碼解析——面試題24二叉搜尋樹的後序遍歷序列

劍指offer程式碼解析——面試題24二叉搜尋樹的後序遍歷序列

本題有bug,歡迎大神指教!

/**
 * 題目:輸入一個整數陣列,判斷該陣列書不是某二叉搜尋數的後序遍歷的結果。如果是返回true,否則返回false。假設輸入的陣列的任意兩個數字都互不重複。
 * @author 大閒人柴毛毛
 * @date 2016年3月15日
 */
public class SearchTree {
	/**
	 * 分析:看過題目後本題最直觀的思路就是通過後序遍歷序列還原這棵二叉樹,然後判斷該二叉樹是否為二叉搜尋樹。
	 * 然而學過資料結構就會知道,如果給一棵二叉樹的中序遍歷和後序遍歷序列,就能唯一確定一棵二叉樹。
	 * 但本題只給了後序遍歷序列,因此無法唯一確定這棵樹。
	 * 那麼,我們能否通過後序遍歷序列把所有可能的二叉樹都羅列出來,然後從中尋找是否有二叉搜尋樹存在。
	 * 這種窮舉的方法需要時間、空間的開銷都很大,這顯然不是種好方法。
	 * 下面,我們從二叉搜尋樹和後序遍歷這兩個條件入手,探尋二叉搜尋樹的後序遍歷序列的特點。
	 */
	
	/**
	 * 後序遍歷的特點:由於後序遍歷先訪問左子樹,再訪問右子樹,最後訪問根結點,因此根結點一定在序列的末尾。
	 * 二叉搜尋樹的特點:二叉搜尋樹的左子樹上所有結點均小於根結點,右子樹上所有結點均大於根結點。
	 * 把這兩個特點結合起來我們可以得出以下結論:在二叉搜尋樹的後序遍歷序列中,根結點一定在序列末尾,且前半段的所有結點均小於根結點,後半段的所有結點均大於根結點。
	 * 因此,可以採用遞迴。按照上述方法不斷劃分序列,直到序列長度小於等於3時不再劃分,且作如下判斷:
	 * 1.若當前序列長度等於3,則表示當前序列為一棵具有三個結點的二叉搜尋樹,因此第一個結點必小於第三個結點,第二個結點必大於第三個結點。若不滿足這個條件則無法組成一棵二叉搜尋樹。
	 * 2.若當前序列長度等於2,則表示當前序列為一棵具有兩個結點的二叉搜尋樹,因此第二個結點為根結點,第一個結點可能是左子樹,也可能是右子樹,因此這兩個結點不管誰大誰小都可以組成一棵二叉搜尋樹。
	 */
	
	/**
	 * 判斷輸入的後序遍歷序列能否構成一棵二叉搜尋樹
	 * @param a 後序遍歷序列
	 * @param start 序列起始下標
	 * @param end 序列結束下標
	 * @return 返回判斷的結果
	 */
	public static boolean isSearchTree(int[] a,int start,int end){
		//若陣列為空
		if(a==null || a.length<=0){
			System.out.println("後序遍歷序列為空!");
			return false;
		}
		
		//若下標越界
		if(start<0 || end>=a.length){
			System.out.println("start、end越界!");
			return false;
		}
		
		//若當前序列長度為3
		if(end-start==2){
			System.out.println("當前序列長度=3……");
			//第一個結點必需要小於第三個結點,第二個結點必須要大於第三個結點,否則就無法構成二叉搜尋樹
			if(a[start]>a[end] || a[start+1]<a[end])
				return false;
			else
				return true;
		}
		
		//若整棵樹只有一個結點、當前序列長度為2直接返回true
		else if(end-start<=1){
			System.out.print("當前序列長度<3……");
			for(int x=start;x<=end;x++)
				System.out.println(a[x]+",");
			return true;
		}
		
		//若當前序列長度超過3,則繼續分隔本序列
		else{
			System.out.print("當前序列長度>3……");
			for(int x=start;x<=end;x++)
				System.out.println(a[x]+",");
			//獲取末尾的根結點
			int root = a[end];
			//尋找根的左子樹與右子樹的分界點
			int i=start;
			while(i<end && a[i]<root)
				i++;//i停止時得到的是後半段的起點
			//判斷後半段結點是否都大於根結點
			for(int j=i;j<end;j++){
				if(a[j]<root)
					return false;
			}
			//若後半段的結點均大於根結點,則進行進入遞迴
			//判斷前半段是否為二叉搜尋樹的後序遍歷序列
			//若當前序列均大於根結點
			boolean result_tail = true;
			boolean result_pre = true;
			if(start>end)
				result_tail = isSearchTree(a,start,end-1);
			else{
				result_pre = isSearchTree(a,start,i-1);
				//判斷後半段是否為二叉搜尋樹的後序遍歷序列
				result_tail = isSearchTree(a,i,end);
			}
			if(result_pre && result_tail)
				return true;
			return false;
		}
	}
	
	
	
	/**
	 * 測試
	 */
	public static void main(String[] args){
		int[] a = {5,7,6,9,11,10,8};
		System.out.println("5,7,6,9,11,10,8:"+isSearchTree(a,0,a.length-1));
	}
}