一,問題描述
給定一棵二叉樹 和 一個整數,打印出二叉樹中結點值的和為給定的整數的所有路徑。注意:路徑是指:從二叉樹的根結點開始的,往下一直到葉子結點過程中 所經過的結點(包括根結點(起點)和葉子結點(終點))。
其中,關於二叉樹相關知識可參考:二叉查找樹的遞歸實現及遞歸分析(http://www.cnblogs.com/hapjin/p/5390451.html)
二,算法分析
應用了遞歸的先序遍歷。先序遍歷每個結點,將先序遍歷的每個結點的和相加,相加的結果是給定的整數,則找到一條路徑並打印之。
定義一個整型變量currentSum,保存當前訪問到的路徑上的結點之和;定義一個棧用來保存當前的路徑。為什么用棧?因為這樣可以與遞歸的先序遍歷同步。
用了棧之后,如何打印路徑?JAVA的LinkedList類的 descendingIterator()方法返回一個可以逆序遍歷鏈表的迭代器。
結點中的值,即可以為正數 也可以為負數嗎?答案是可以。因為,路徑必須是從根到葉子結點,且整個遞歸調用會一直調用到葉子后才會返回。
代碼實現如下:
1 public void findExpectedSumPath(BinaryNode root, int expectedSum){ 2 if(root == null) 3 return; 4 LinkedList<BinaryNode> stack = new LinkedList<BinaryNode>(); 5 int currentSum = 0; 6 findExpectedSumPath(root, expectedSum, currentSum, stack); 7 } 8 private void findExpectedSumPath(BinaryNode root, int expectedSum, int currentSum, LinkedList<BinaryNode> stack){ 9 currentSum += root.element; 10 stack.push(root); // visit root 11 12 boolean isLeaf = (root.left == null && root.right == null); 13 if(currentSum == expectedSum && isLeaf){//print path 14 Iterator<BinaryNode> it = stack.descendingIterator();//逆序遍歷List(Stack) 15 while(it.hasNext()) 16 System.out.print(it.next().element + " "); 17 18 System.out.println(); 19 }//end if 20 21 if(root.left != null)//visit left sub tree 22 findExpectedSumPath(root.left, expectedSum, currentSum, stack); 23 if(root.right != null)//visit right sub tree 24 findExpectedSumPath(root.right, expectedSum, currentSum, stack); 25 26 stack.pop();//當某結點左右孩子均為null時, 回退 27 }
可以看出:上面的代碼是一個二叉樹的先序遍歷的典型應用!第9,10行表示:訪問根結點[然后進行了一系列的處理(12-19行)];第21、22行表示訪問根的左子樹;第23、24行表示訪問根的右子樹。
當遍歷到葉子結點時,在第26行,保存路徑的棧會 pop,這相當於路徑的回退。
三,擴展
如果給定的樹中的結點值都是正數,且路徑只需要從根結點開始,路徑的終點不一定是葉子結點
這里,當currentSum > expectedSum時,就不需要再向下進行遞歸調用了。因為,結點值都是正數,再向下遞歸調用只會是currentSum越來越大。
比如,expectedSum為 13,當遍歷到結點6時,currentSum=8+6=14 了,就不需要再向下進行遍歷了。
如果expectedSum=14,那么遍歷到6之后,也不需要再向下遍歷了。總之,只有當currentSum 小於 expectedSum時,才需要向下進行遍歷。代碼實現如下:
1 public void findExpectedSumPath2(BinaryNode root, int expectedSum){ 2 if(root == null) 3 return; 4 LinkedList<BinaryNode> stack = new LinkedList<BinaryNode>(); 5 int currentSum = 0; 6 findExpectedSumPath2(root, expectedSum, currentSum, stack); 7 } 8 private void findExpectedSumPath2(BinaryNode root, int expectedSum, int currentSum, LinkedList<BinaryNode> stack){ 9 currentSum += root.element; 10 stack.push(root); 11 12 // boolean isLeaf = (root.left == null && root.right == null); 13 if(currentSum == expectedSum){//print path 14 Iterator<BinaryNode> it = stack.descendingIterator();//逆序遍歷List(Stack) 15 while(it.hasNext()) 16 System.out.print(it.next().element + " "); 17 18 System.out.println(); 19 }//end if 20 21 //當currentSum > expectedSum時 再往下遞歸沒有意義了 22 if(currentSum < expectedSum){ 23 if(root.left != null) 24 findExpectedSumPath2(root.left, expectedSum, currentSum, stack); 25 if(root.right != null) 26 findExpectedSumPath2(root.right, expectedSum, currentSum, stack); 27 } 28 29 stack.pop();//當某結點左右孩子均為null時, 回退 30 }
完整代碼如下:
import java.util.Iterator; import java.util.LinkedList; import java.util.Queue; public class ExpectedSumPath { private class BinaryNode{ int element; BinaryNode left; BinaryNode right; public BinaryNode(int ele) { element = ele; this.left = this.right = null; } } private BinaryNode root;//樹根 public void insert(int element){ root = insert(element, root); } private BinaryNode insert(int element, BinaryNode root){ if(root == null) return new BinaryNode(element); if (element > root.element) root.right = insert(element, root.right); else if(element < root.element) root.left = insert(element, root.left); else ; return root; /** if(Math.random() > 0.5)//insert a node randomly in left nodes root.left = insert(element, root.left); else root.right = insert(element, root.right); return root; */ } public void printTree(BinaryNode root){ if(root == null) return; Queue<BinaryNode> queue = new LinkedList<>(); int current;//當前層 還未打印的結點個數 int next;//下一層結點個數 queue.offer(root); current = 1; next = 0; while(!queue.isEmpty()){ BinaryNode currentNode = queue.poll(); System.out.printf("%-4d", currentNode.element); current--; if(currentNode.left != null){ queue.offer(currentNode.left); next++; } if(currentNode.right != null){ queue.offer(currentNode.right); next++; } if(current ==0){ System.out.println(); current = next; next = 0; } } } public void findExpectedSumPath(BinaryNode root, int expectedSum){ if(root == null) return; LinkedList<BinaryNode> stack = new LinkedList<BinaryNode>(); int currentSum = 0; findExpectedSumPath(root, expectedSum, currentSum, stack); } private void findExpectedSumPath(BinaryNode root, int expectedSum, int currentSum, LinkedList<BinaryNode> stack){ currentSum += root.element; stack.push(root); boolean isLeaf = (root.left == null && root.right == null); if(currentSum == expectedSum && isLeaf){//print path Iterator<BinaryNode> it = stack.descendingIterator();//逆序遍歷List(Stack) while(it.hasNext()) System.out.print(it.next().element + " "); System.out.println(); }//end if if(root.left != null) findExpectedSumPath(root.left, expectedSum, currentSum, stack); if(root.right != null) findExpectedSumPath(root.right, expectedSum, currentSum, stack); stack.pop();//當某結點左右孩子均為null時, 回退 } public void findExpectedSumPath2(BinaryNode root, int expectedSum){ if(root == null) return; LinkedList<BinaryNode> stack = new LinkedList<BinaryNode>(); int currentSum = 0; findExpectedSumPath2(root, expectedSum, currentSum, stack); } private void findExpectedSumPath2(BinaryNode root, int expectedSum, int currentSum, LinkedList<BinaryNode> stack){ currentSum += root.element; stack.push(root); // boolean isLeaf = (root.left == null && root.right == null); if(currentSum == expectedSum){//print path Iterator<BinaryNode> it = stack.descendingIterator();//逆序遍歷List(Stack) while(it.hasNext()) System.out.print(it.next().element + " "); System.out.println(); }//end if //當currentSum > expectedSum時 再往下遞歸沒有意義了 if(currentSum < expectedSum){ if(root.left != null) findExpectedSumPath2(root.left, expectedSum, currentSum, stack); if(root.right != null) findExpectedSumPath2(root.right, expectedSum, currentSum, stack); } stack.pop();//當某結點左右孩子均為null時, 回退 } public static void main(String[] args) { ExpectedSumPath tree = new ExpectedSumPath(); int[] elements = {20,18,4,19,22}; for (int i : elements) { tree.insert(i); } tree.findExpectedSumPath2(tree.root, 42); } }