java前中后 遍历 递归与非递归

public class TreeTraversal {
    public void preOrder(TreeNode root){
        // 先序递归
        if (root == null){
            return;
        }
        // 根左右 每个节点都访问三次
        System.out.println("root.val = " + root.val);
        preOrder(root.left);
        preOrder(root.right);
    }

    /**
     * 先序遍历非递归写法
     * @param root
     */
    public void preOrderWithoutRecursive(TreeNode root){
        // 问题1 : 忘记校验root
        if (root == null){
            return;
        }
        // 思路 递归本质是栈,借助栈来实现非递归的先序遍历
        LinkedList<TreeNode> stack = new LinkedList<>();
        // 根节点入栈,栈不空就继续遍历
        stack.add(root);
        while (!stack.isEmpty()){
            // 由于先序,直接出栈并打印
            TreeNode popNode = stack.pop();
            // 先序遍历
            System.out.println("popNode.val = " + popNode.val);
            // 子节点入栈,继续遍历,不断的根 左 右
            // 栈结构逆反所以 右 左 入栈
            // 问题2:忘记校验左右非空 牢记参数校验
            if (popNode.right!= null){
                stack.push(popNode.right);
            }

            // 左侧节点永远比右侧先出栈被遍历到
            if (popNode.left!= null){
                stack.push(popNode.left);
            }
        }

    }


    /**
     * 中序遍历
     * @param root
     */
    public void inOrder(TreeNode root){
        // 递归
        if (root == null){
            return;
        }
        // 左根右 每个节点都访问三次
        inOrder(root.left);
        // 中序就是在第二次访问到自身时输出/做事
        System.out.println("root.val = " + root.val);
        inOrder(root.right);
    }

    /**
     * 中序遍历非递归写法
     * @param root
     */
    public void inOrderWithoutRecursive(TreeNode root){
        // 问题1 : 忘记校验root
        if (root == null){
            return;
        }
        // 思路 递归本质是栈,借助栈来实现非递归的中序遍历
        LinkedList<TreeNode> stack = new LinkedList<>();
        // 根节点入栈,栈不空就继续遍历
        stack.add(root);
        while (!stack.isEmpty()){
            // 如果遍历左侧非空则一直入栈
            if(root.left != null){
                stack.push(root.left);
                root = root.left;
            }else{
                // 遍历到左侧底部,由于一层循环
                // 直接出栈并访问
                TreeNode popNode = stack.pop();
                System.out.println(popNode.val);
                // 判断是否需要访问右侧
                if(popNode.right != null){
                    root = popNode.right;
                    stack.push(popNode.right);
                }
            }


        }

    }

    /**
     * 中序遍历非递归写法
     * @param root
     */
    public void inOrderWithoutRecursive1(TreeNode root){
        // 问题1 : 忘记校验root
        if (root == null){
            return;
        }
        // 思路 递归本质是栈,借助栈来实现非递归的中序遍历
        LinkedList<TreeNode> stack = new LinkedList<>();
        // 优化 直接遍历 更加符合语义
        while (root != null || !stack.isEmpty()){
            // 如果遍历左侧非空则一直入栈
            if(root != null){
                // 直接放入而不是左侧了
                stack.push(root);
                root = root.left;
            }else{
                // 遍历到左侧底部,由于一层循环
                // 直接出栈并访问
                TreeNode popNode = stack.pop();
                System.out.println(popNode.val);
                // 优化 直接访问右侧
                root = popNode.right;
            }


        }

    }

    /**
     * 后序遍历
     * @param root
     */
    public void postOrder(TreeNode root){
        // 递归
        if (root == null){
            return;
        }
        // 左右根 每个节点都访问三次
        postOrder(root.left);
        postOrder(root.right);
        // 后序就是在第三次访问到自身时输出/做事
        System.out.println("root.val = " + root.val);
    }

    /**
     * 后序遍历非递归写法
     * @param root
     */
    public void postOrderWithoutRecursive(TreeNode root){
        // 问题1 : 忘记校验root
        if (root == null){
            return;
        }
        // 思路 递归本质是栈,借助栈来实现非递归的后序
        // 后序与先序做比较 先序 根 左 右 后序 左 右 根
        // 后序的逆转 根 右 左
        // 先序非递归是右左入栈所以出栈是左右,后序只要左右入栈出栈就是右左,后序就是先序的逆反+栈输出,出栈入辅助后逆序输出
        LinkedList<TreeNode> stack1 = new LinkedList<>();
        LinkedList<TreeNode> stack2 = new LinkedList<>();
        // 根节点入栈
        stack1.push(root);
        while (!stack1.isEmpty()){
            // 先序是先输出,后序直接入栈 并且由于出栈特性,每个节点都只访问一次 不会出现重复入栈的动作
            TreeNode popNode = stack1.pop();
            stack2.push(popNode);
            // 左右遍历即可
            if (popNode.left != null){
                stack1.push(popNode.left);
            }
            if (popNode.right != null){
                stack1.push(popNode.right);
            }
        }
        while (!stack2.isEmpty()){
            // 错误 应该直接访问stack2
//            System.out.println("stack1.pop().val = " + stack1.pop().val);
            System.out.println("stack2.pop().val = " + stack2.pop().val);
        }


    }

}

   class TreeNode {
      int val;
      TreeNode left;
      TreeNode right;
      TreeNode() {}
      TreeNode(int val) { this.val = val; }
      TreeNode(int val, TreeNode left, TreeNode right) {
          this.val = val;
          this.left = left;
          this.right = right;
      }
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值