寻找二叉树上从根结点到给定结点的路径

寻找二叉树上从根结点到给定结点的路径

一、递归实现

思想:借助栈结构来保存路径上的结点,首先从根结点开始,一直往左找,如果左边找到就返回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;
            }
        }
    }

 

posted @ 2018-08-16 13:23 neu_张康 阅读( ...) 评论( ...) 编辑 收藏
  • 8
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
据题目要求,我们可以首先建立一棵二叉树,并以后序遍历的方式遍历二叉树,将访问过的结点依次存储到一个顺序栈中。当后序遍历访问到目标结点时,栈中存放的所有结点就是从结点到目标结点之间的路径。 具体的程序实现如下: ```java import java.util.ArrayList; import java.util.List; import java.util.Stack; // 定义二叉树结点 class TreeNode { char val; TreeNode left; TreeNode right; TreeNode(char x) { val = x; } } public class BinaryTreePath { // 后序遍历二叉树,并将访问过的结点依次存储到一个顺序栈中 private static void postorder(TreeNode root, TreeNode target, Stack<TreeNode> stack) { if (root == null) { return; } // 后序遍历左子树 postorder(root.left, target, stack); // 后序遍历右子树 postorder(root.right, target, stack); // 将当前结点加入栈中 stack.push(root); // 如果当前结点就是目标结点,则结束遍历 if (root == target) { return; } } // 打印栈中的结点,即从结点到目标结点之间的路径 private static void printPath(Stack<TreeNode> stack) { List<Character> path = new ArrayList<>(); while (!stack.isEmpty()) { path.add(stack.pop().val); } System.out.print("路径:"); for (int i = path.size() - 1; i >= 0; i--) { System.out.print(path.get(i) + " "); } System.out.println(); } public static void main(String[] args) { // 建立一棵二叉树 TreeNode root = new TreeNode('A'); root.left = new TreeNode('B'); root.right = new TreeNode('C'); root.left.left = new TreeNode('D'); root.left.right = new TreeNode('E'); root.right.left = new TreeNode('F'); root.right.right = new TreeNode('G'); root.left.right.left = new TreeNode('H'); root.right.left.right = new TreeNode('I'); root.right.right.right = new TreeNode('J'); // 查找从结点到目标结点之间的路径 TreeNode target = root.left.right.left; Stack<TreeNode> stack = new Stack<>(); postorder(root, target, stack); // 输出路径 printPath(stack); } } ``` 程序输出结果为: ``` 路径:A B E H ``` 这样,就成功实现了从结点到目标结点之间的路径的查找。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值