二叉树中的和为某一值的路径
一,问题描述
给定一棵二叉树 和 一个整数,打印出二叉树中结点值的和为给定的整数的所有路径。注意:路径是指:从二叉树的根结点开始的,往下一直到叶子结点过程中 所经过的结点(包括根结点(起点)和叶子结点(终点))。
其中,关于二叉树相关知识可参考:二叉查找树的递归实现及递归分析(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); } }