【LeetCode笔记】94 & 144 & 145. 二叉树的前序、中序、后序遍历的迭代与递归(Java、dfs、迭代)

直接来个整合吧,也方便看。之前只写了递归的,现在补上迭代的(迭代才是考点!)
是面试高频题,要好好掌握好各自间的区分哦!

一. 题目描述

题目描述基本上一样,就只展示中序的题干了
在这里插入图片描述

二. 代码 & 思路

1. 递归的写法

  • 这里比较简单,就不赘述了,就是换换顺序。
/**
 * Definition for a binary tree node.
 * public 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;
 *     }
 * }
 */
class Solution {
	List<Integer> ans = new ArrayList<>();
    public List<Integer> inorderTraversal(TreeNode root) {
        mid(ans);
        return ans;
    }
    // 前序
    void first(TreeNode root){
        if(root == null){
            return;
        }
        ans.add(root.val);
        first(root.left);
        first(root.right);
    }
    // 中序
    void mid(TreeNode now){
        if(now == null){
            return;
        }
        mid(now.left);
        ans.add(now.val);
        mid(now.right);
    }
    // 后序
    void last(TreeNode now){
        if(now == null){
            return;
        }
        last(now.left);
        last(now.right);
        ans.add(now.val);
    }
}

2. 迭代的写法(本文重点来了)

说实话,三份代码简直模版:while & if else & stack,写的前五行代码是一样的

  • 首先明确一点,栈的作用
  • 前面的递归写法,就是 JVM 隐式地帮我们进行了栈的操作
  • 迭代:用栈模仿虚拟机的调用过程
  • 前序 & 中序很像,后序相对难一点,需要维护一个 pre 结点
1) 前序
class Solution {
    List<Integer> ans = new ArrayList<>();
    public List<Integer> preorderTraversal(TreeNode root) {
        // 迭代:通过栈模拟虚拟机的递归结构
        Stack<TreeNode> myStack = new Stack<>();
        TreeNode now = root;
        // 前中后写的前五行代码都是一样的
        while(now != null || !myStack.isEmpty()){
            // 非null情况:先加再说!入栈,然后直接往左走
            if(now != null){
                ans.add(now.val);
                myStack.push(now);
                now = now.left;
            }
            // null情况:那就走父结点的右边!
            else {
                now = myStack.pop().right;
            }
        }
        return ans;
    }
}
2) 中序
  • 和前序相比,都是一路向左,到头了就取父结点的右边
  • 不同之处在于,ans.add的位置,前序 & 中序分布在 if else 中
class Solution {
    List<Integer> ans = new ArrayList<>();
    public List<Integer> inorderTraversal(TreeNode root) {
        // 迭代:用栈模仿虚拟机的调用过程
        Stack<TreeNode> myStack = new Stack<>();
        TreeNode now = root;
        // 结束条件:当前结点已经走到底,并且栈中也无可用结点了
        while(now != null || !myStack.isEmpty()){
            // 非null情况:入栈,一路向左
            if(now != null){
                myStack.push(now);
                now = now.left;
            }
			// null情况:左到头了,取出父节点,加入答案,然后从父结点的右结点继续
            else{
				TreeNode temp = myStack.pop();
                ans.add(temp.val);
                now = temp.right;
            }
        }
        return ans;
    }
}
3) 后序
  • 非null情况处理,和中序完全一样
  • 唯一一个使用了peek的,也就是说:null情况不一定会pop
  • 代码重点在于:null 情况部分,详细见代码
  • pre 的更新是从底向上的(有点抽象,结合代码可能比较好理解)
class Solution {
    List<Integer> ans = new ArrayList<>();
    public List<Integer> postorderTraversal(TreeNode root) {
        Stack<TreeNode> myStack = new Stack<>();
        TreeNode now = root;
        // 相对于前序 & 中序,此处加了个 pre 结点,用来验证右边结点是否走过
        TreeNode pre = null;
        while(now != null || !myStack.isEmpty()){
            // 非null情况:先 push 当前结点,然后往左冲!
            if(now != null){
                myStack.push(now);
                now = now.left;
            }
            // null情况:冲到头了
            else{
                // 注意这里是 peek,不一定 pop 掉
                now = myStack.peek();
                // 取答案的情况:父结点无右结点 Or 父节点的右结点已走过
                if(now.right == null || now.right == pre){
                    ans.add(now.val);
                    // 更新 pre 值为当前值,表示当前值已走过,供now的父节点使用
                    pre = now;
                    // pop 掉父节点
                    myStack.pop();
                    // 更新 now 为 null,下一次循环继续peek
                    now = null;
                }
                // 可以继续走右边的情况
                else{
                    now = now.right;
                }
            }
        }
        return ans;
    }  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值