1. 程式人生 > 其它 >劍指offer程式碼解析——面試題25二叉樹中和為某一值的路徑

劍指offer程式碼解析——面試題25二叉樹中和為某一值的路徑

題目:輸入一棵二叉樹和一個整數,打印出二叉樹中結點值的和為輸入整數的所有路徑。PS:從根結點開始,一直到葉子結點形式一條路徑。

分析:要找出路徑之和為指定整數的路徑,就需要遍歷二叉樹的所有路徑。此外,由於路徑是指根結點到葉子結點的線段,因此我們想到採用深度優先的方式遍歷二叉樹。深度優先演算法又分為:先序遍歷、中序遍歷、後序遍歷,其中先序遍歷符合我們的要求。

首先需要建立一個棧,用來儲存當前路徑的結點。採用先序遍歷演算法遍歷結點時,先將途中經過的結點均存入棧中,然後判斷當前結點是否為葉子結點,若不是葉子結點的話,則遞迴遍歷該結點的左孩子和右孩子;若是葉子結點的話,計算下當前棧中所有結點之和是否為指定的整數,若是的話列印棧中所有元素。然後這個函式在返回之前,將當前葉子結點從棧中刪除。程式碼如下:

/**
 * 題目:輸入一棵二叉樹和一個整數,打印出二叉樹中結點值的和為輸入整數的所有路徑。
 * PS:從根結點開始,一直到葉子結點形式一條路徑。
 * @author 大閒人柴毛毛
 * @date 2016年3月15日
 */
public class PrintBinaryPath {
	/**
	 * 分析:要找出路徑之和為指定整數的路徑,就需要遍歷二叉樹的所有路徑。
	 * 此外,由於路徑是指根結點到葉子結點的線段,因此我們想到採用深度優先的方式遍歷二叉樹。
	 * 深度優先演算法又分為:先序遍歷、中序遍歷、後序遍歷,其中先序遍歷符合我們的要求。
	 */
	
	/**
	 * 首先需要建立一個棧,用來儲存當前路徑的結點。
	 * 採用先序遍歷演算法遍歷結點時,先將途中經過的結點均存入棧中,然後判斷當前結點是否為葉子結點,若不是葉子結點的話,則遞迴遍歷該結點的左孩子和右孩子;
	 * 若是葉子結點的話,計算下當前棧中所有結點之和是否為指定的整數,若是的話列印棧中所有元素。
	 * 然後這個函式在返回之前,將當前葉子結點從棧中刪除。
	 */
	
	/**
	 * 列印二叉樹中路徑之和為n的路徑
	 * @param root 二叉樹
	 * @param n 路徑之和
	 * @return 返回函式能否正確執行
	 */
	public static boolean printBinaryPath(BinaryTreeNode<Integer> root,int n){
		//樹為空
		if(root==null){
			System.out.println("樹為空!");
			return false;
		}
		
		//n小於0
		if(n<=0){
			System.out.println("n小於等於0!");
			return false;
		}
		
		//建立棧
		Stack<Integer> stack = new Stack<Integer>();
		//開始遞迴查詢路徑
		printBinaryPath(root,n,stack);
		
		return true;
	}

	
	
	/**
	 * 遞迴尋找路徑之和為n的路徑
	 * @param root 二叉樹根結點
	 * @param n 指定整數
	 * @param stack 用於儲存當前路徑的棧
	 */
	private static void printBinaryPath(BinaryTreeNode<Integer> root, int n, Stack<Integer> stack) {
		//若當前根結點為葉子結點
		if(root.left==null && root.right==null){
			//將葉子結點入棧
			stack.add(root.data);
			
			//計算當前路徑之和
			int sum = 0;
			Iterator<Integer> it = stack.iterator();
			while(it.hasNext())
				sum += it.next();
			
			//若當前路徑之和==n,則列印這條路徑
			if(sum==n){
				Iterator<Integer> it2 = stack.iterator();
				while(it2.hasNext())
					System.out.print(it2.next()+",");
				System.out.println("n-------------------");
			}
			
			//將當前葉子結點出棧
			stack.pop();
			
			//返回上層結點
			return;
		}
		
		//若當前結點為非葉子結點
		else{
			//將根結點入棧
			stack.add(root.data);
			
			//若左孩子存在,遞迴左孩子
			if(root.left!=null)
				printBinaryPath(root.left,n,stack);
			
			//若右孩子存在,遞迴右孩子
			if(root.right!=null)
				printBinaryPath(root.right,n,stack);
			
			//將當前葉子結點出棧
			stack.pop();
			
			//返回上層結點
			return;
		}
	}
	
	
	
	/**
	 * 測試
	 */
	public static void main(String[] args){
		//構建二叉樹
		BinaryTreeNode<Integer> node1 = new BinaryTreeNode<Integer>();
		BinaryTreeNode<Integer> node2 = new BinaryTreeNode<Integer>();
		BinaryTreeNode<Integer> node3 = new BinaryTreeNode<Integer>();
		BinaryTreeNode<Integer> node4 = new BinaryTreeNode<Integer>();
		BinaryTreeNode<Integer> node5 = new BinaryTreeNode<Integer>();
		
		node1.data = 10;
		node2.data = 5;
		node3.data = 12;
		node4.data = 4;
		node5.data = 7;
		
		node1.left = node2;
		node1.right = node3;

		node2.left = node4;
		node2.right = node5;
		
		printBinaryPath(node1,19);
	}
}




/**
 * 二叉樹的結點
 */
class BinaryTreeNode<T>{
	T data;//結點的資料域
	BinaryTreeNode<T> left;//左子樹
	BinaryTreeNode<T> right;//右子樹
}