寻找二叉树上从根结点到给定结点的路径
一、递归实现
思想:借助栈结构来保存路径上的结点,首先从根结点开始,一直往左找,如果左边找到就返回true;否则,如果左边找不到并且右子树不为空的情况下再继续往右子树找。如果左右子树都找不到,就弹出栈顶结点并返回false。方法运行完毕后,栈中保存的元素就是一条从根到给定结点的路径。
public static boolean searchNode(TreeNode root,Stack<TreeNode> s,TreeNode node) { if(root == null) return false; s.push(root); if(root.val == node.val) return true; boolean b = false; //先去左子树找 if(root.left != null) b = searchNode(root.left,s,node); //左子树找不到并且右子树不为空的情况下才去找 if(!b && root.right != null) b = searchNode(root.right,s,node); //左右都找不到,弹出栈顶元素 if(!b) s.pop(); return b; }
程序运行结束后,栈中保存的就是要求的路径,参数root代表根节点,s代表栈,node代表给定的节点。如果不想用值来比较,就直接把if(root.val == node.val)换成if(root == node),道理都是一样的。
二、非递归实现
思想:这个稍微有些复杂,当然也是要借助栈来完成。其实这里和二叉树的非递归先序遍历的思想差不多,只是在这个基础上进行一些改造。首先,新建一个栈,保存根节点。然后开始一直向左查找,查找的过程中把结点入栈。如果在向左找的过程中遇到了给定的结点,那么就输出并返回,这个过程比较好理解。关键是下面的弹栈的过程,如果在向左找的过程中遇到了null,说明当前栈顶元素的左子树为null。那么我们向栈顶元素的右子树开始查找。令p为栈顶元素,如果栈顶元素的右子树为null,那么弹出栈顶元素,并用pre来保存刚弹出的元素,之所以设置pre,是因为如果当前栈顶元素的右子树不为null的时候,不能轻易弹出,首先得去右子树上去查找,如果右孩子被弹出了,说明右子树上肯定没有,那么当前结点才可以弹出。
public static void searchNode(TreeNode root,TreeNode node) { if(root == null || node == null) return; Stack<TreeNode> s = new Stack<>(); TreeNode p = root; TreeNode pre = null; //上一次出栈的结点 while(p != null || !s.isEmpty()) { while(p != null) { //这个while循环的思想还是一直往左找,找的过程结点入栈,如果找到了就打印输出并返回。 s.push(p); if(p.val == node.val) { for (TreeNode treeNode : s) { System.out.print(treeNode.val + " "); } return; } p = p.left; } //走到这一步说明栈顶元素的左子树为null,那么就开始往栈顶元素的右子树上去找。 if(!s.isEmpty()) { p = s.peek(); //如果栈顶元素的右子树为null,或者右子树被遍历过,则弹栈。 while(p.right == null || pre != null && p.right == pre) { pre = s.pop(); p = s.peek(); } //继续遍历p的右子树 p = p.right; } } }