前中后序遍历,层次遍历(递归和非递归法)

四种主要的遍历思想为:

前序遍历:根结点 —> 左子树 —> 右子树

中序遍历:左子树—> 根结点 —> 右子树

后序遍历:左子树 —> 右子树 —> 根结点

层次遍历:只需按层次遍历即可
在这里插入图片描述

前序遍历

  • 递归法:
public class LC144 {
    //递归法:
    public List<Integer> preorderTraversal(TreeNode root) {
        ArrayList<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        helper(root, list);
        return list;
    }

    private void helper(TreeNode root, ArrayList<Integer> list) {
        if (root == null) {
            return;
        }
        list.add(root.val);
        helper(root.left, list);
        helper(root.right, list);
    }
}

  

  • 非递归法:
public class LC144 {
    //非递归法:
    public List<Integer> preorderTraversal(TreeNode root) {
        ArrayList<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.push(root);
        while (!stack.isEmpty()) {
            root = stack.pop(); //或者写成 TreeNode tmp = stack.pop();
            list.add(root.val);
            if (root.right != null) {
                stack.push(root.right);
            }
            if (root.left != null) {
                stack.push(root.left);
            }
        }
        return list;
    }
}

  

中序遍历

  • 递归法:
public class LC94 {
    //递归法:
    public List<Integer> inorderTraversal(TreeNode root) {
        ArrayList<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        helper(root, list);
        return list;
    }

    private void helper(TreeNode root, ArrayList<Integer> list) {
        if (root == null) {
            return;
        }
        helper(root.left, list);
        list.add(root.val);
        helper(root.right, list);
    }
}

  

  • 非递归法:
public class LC94 {
    //非递归法:
    public List<Integer> inorderTraversal(TreeNode root) {
        ArrayList<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack<>();
        while (!stack.isEmpty() || root != null) {
            if (root != null) {
                stack.push(root);
                root = root.left;
            } else {
                root = stack.pop();
                list.add(root.val);
                root = root.right;
            }
        }
        return list;
    }
}

  

后序遍历

  • 递归法:
public class LC145 {
    //递归法
    public List<Integer> postorderTraversal(TreeNode root) {
        ArrayList<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        helper(root, list);
        return list;
    }

    private void helper(TreeNode root, ArrayList<Integer> list) {
        if (root == null) {
            return;
        }
        helper(root.left, list);
        helper(root.right, list);
        list.add(root.val);
    }
}

  

  • 非递归法:
public class LC145 {
    //非递归法
    public List<Integer> postorderTraversal(TreeNode root) {
        ArrayList<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        Stack<TreeNode> s1 = new Stack<>();
        Stack<TreeNode> s2 = new Stack<>();
        s1.push(root);
        while (!s1.isEmpty()) {
            root = s1.pop(); //或者写成 TreeNode tmp = s1.pop();
            s2.push(root);
            if (root.left != null) {
                s1.push(root.left);
            }
            if (root.right != null) {
                s1.push(root.right);
            }
        }
        while (!s2.isEmpty()) {
            list.add(s2.pop().val);
        }
        return list;
    }
}

  

层次遍历

  • 递归法:
public class LC102 {
	//递归法
    public List<List<Integer>> levelOrderDFS(TreeNode root) {
        ArrayList<List<Integer>> lists = new ArrayList<>();
        helper(root, 0, lists);
        return lists;
    }

    private void helper(TreeNode root, int level, ArrayList<List<Integer>> lists) {
        if (root == null) {
            return;
        }
        //当前层还没有元素,先new一个空的列表
        if (lists.size() <= level) {
            lists.add(new ArrayList<>());
        }
        lists.get(level).add(root.val);
        helper(root.left, level + 1, lists);
        helper(root.right, level + 1, lists);
    }
}

  

  • 非递归:
    //如果要求每层节点分类存储
    public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) {
        ArrayList<ArrayList<Integer>> res = new ArrayList<>();
        if (root == null) {
            return res;
        }
        LinkedList<TreeNode> list = new LinkedList<>();
        list.add(root);
        int level = 0;
        while (!list.isEmpty()) {
            res.add(new ArrayList<>());
            int len = list.size();
            for (int i = 0; i < len; i++) {
                TreeNode node = list.pop();
                res.get(level).add(node.val);
                if (node.left != null) {
                    list.add(node.left);
                }
                if (node.right != null) {
                    list.add(node.right);
                }
            }
            level++;
        }
        return res;
    }


整体:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Stack;

public class Order {
    public void preOrder(Node head) {
        if (head == null) {
            return;
        }
        Stack<Node> s = new Stack<>();
        s.push(head);
        while (!s.isEmpty()) {
            head = s.pop();
            System.out.println(head.val);
            if (head.right != null) {
                s.push(head.right);
            }
            if (head.left != null) {
                s.push(head.left);
            }
        }
    }

    public void inOrder(Node head) {
        if (head == null) {
            return;
        }
        Stack<Node> s = new Stack<>();
        while (!s.isEmpty() || head != null) {
            if (head != null) {
                s.push(head);
                head = head.left;
            } else {
                head = s.pop();
                System.out.println(head.val + " ");
                head = head.right;
            }
        }
    }

    public void postOrder(Node head) {
        if (head == null) {
            return;
        }
        Stack<Node> s1 = new Stack<>();
        Stack<Node> s2 = new Stack<>();
        s1.push(head);
        while (!s1.isEmpty()) {
            head = s1.pop();
            s2.push(head);
            if (head.left != null) {
                s1.push(head.left);
            }
            if (head.right != null) {
                s1.push(head.right);
            }
        }
        while (!s2.isEmpty()) {
            System.out.println(s2.pop().val + " ");
        }
    }

    public ArrayList<ArrayList<Integer>> levelOrder(Node head) {
        ArrayList<ArrayList<Integer>> res = new ArrayList<>();
        if (head == null) {
            return res;
        }
        LinkedList<Node> list = new LinkedList<>();
        list.add(head);
        int level = 0;
        while (!list.isEmpty()) {
            res.add(new ArrayList<>());
            int len = list.size();
            for (int i = 0; i < len; i++) {
                Node node = list.pop();
                res.get(level).add(node.val);
                if (node.left != null) {
                    list.add(node.left);
                }
                if (node.right != null) {
                    list.add(node.right);
                }
            }
            level++;
        }
        return res;
    }

    /**
     * 递归思路
     */
    public void preOrderR(Node head) {
        if (head == null) {
            return;
        }
        System.out.println(head.val + " ");
        preOrderR(head.left);
        preOrderR(head.right);
    }

    public void inOrderR(Node head) {
        if (head == null) {
            return;
        }
        inOrderR(head.left);
        System.out.println(head.val + " ");
        inOrderR(head.right);
    }

    public void postOrderR(Node head) {
        if (head == null) {
            return;
        }
        postOrderR(head.left);
        postOrderR(head.right);
        System.out.println(head.val + " ");
    }
}
<think>好的,我现在需要帮助用户理解二叉后序遍历非递归实现方法,并提供代码解析。用户之已经询问过先序遍历非递归实现,现在转向后序,所以我需要确保解释清晰,并比较两者的不同。 首先,我得回忆后序遍历的顺序是左-右-根,这意味着在处理当节点之,必须先访问完左右子非递归实现通常需要使用栈来模拟递归过程,但后序的情况比先序中序更复杂,因为需要跟踪节点的访问状态。 根据用户提供的引用[1],里面提到后序遍历非递归写法最难,可能需要双栈法或标记法。引用[4]中的中序遍历代码使用了一个栈,通过移动指针来遍历左子,然后处理根节点右子。但后序需要更多的控制,确保左右子都被访问过才能处理当节点。 标记法可能更容易理解,即在栈中存储节点访问状态的组合。例如,使用一个标记来指示节点是否是第一次弹出。如果是第一次,则重新入栈并处理右子节点,第二次弹出时才访问节点值。这种方法可以确保左右子处理完毕后再处理根节点。 另外,引用[5]提到Java的后台开发中使用AOF重写机制,但可能问题无关,可以忽略。引用[3]中的练习题可能涉及遍历的应用,但用户现在需要的是实现方法。 我需要一步步拆解代码,解释每个步骤的作用。例如,使用栈来保存节点标记,初始时压入根节点未访问状态。然后循环处理栈顶元素,根据标记决定是处理子节点还是访问当节点。 同时,需要比较先序、中序后序的不同之处。例如,先序在入栈时访问节点,后序则需要在第二次弹出时访问。还要注意入栈顺序,确保左子节点先处理,然后是右子节点,最后是根节点。 还需要考虑边界情况,比如空或单节点的情况。代码中需要检查root是否为null,并返回空列表。栈的操作需要正确,避免空指针异常。 最后,给出时间复杂度分析,说明时间空间复杂度都是O(n),因为每个节点入栈两次,但总次数仍与节点数成线性关系。空间复杂度由栈的深度决定,最坏情况下是O(n),平衡时为O(log n)。 可能用户还会想知道为什么后序遍历比其他遍历难,所以需要解释跟踪节点的必要性,以及如何通过标记法解决这个问题。同时,引用相关参考资料中的信息,如[^1][^4],来支持解释的正确性。</think>### 二叉后序遍历非递归实现及代码解析 后序遍历的顺序是**左子 → 右子 → 根节点**。非递归实现的核心难点在于:**必须确保左右子都被访问后才能处理当节点**。这里提供两种主流实现方法,并给出详细解析。 --- #### 方法一:双栈法(反向先序) **核心思想**:通过调整先序遍历的入栈顺序(根 → 右 → 左),将结果反向输出即可得到后序序列。 ```java public List<Integer> postOrderNonRecursive(TreeNode root) { List<Integer> result = new ArrayList<>(); if (root == null) return result; Stack<TreeNode> stack = new Stack<>(); Stack<Integer> output = new Stack<>(); // 辅助栈用于反向输出 stack.push(root); while (!stack.isEmpty()) { TreeNode node = stack.pop(); output.push(node.val); // 先存入辅助栈 if (node.left != null) stack.push(node.left); // 注意入栈顺序 if (node.right != null) stack.push(node.right); } while (!output.isEmpty()) { result.add(output.pop()); // 反向输出即为后序序列 } return result; } ``` **步骤解析**(以二叉 `1 -> 2(),3()` 为例): 1. **主栈初始化**:`1`入栈 2. **第一次循环**: - 弹出`1`,存入辅助栈 → `output=[1]` - `2``3`按左→右顺序入主栈 → `stack=[2,3]` 3. **第二次循环**: - 弹出`3`,存入辅助栈 → `output=[1,3]` - `3`的左右子节点为空 4. **第三次循环**: - 弹出`2`,存入辅助栈 → `output=[1,3,2]` 5. **反向输出**:最终结果为`2 → 3 → 1` --- #### 方法二:标记法(单栈追踪状态) **核心思想**:用栈存储节点及其访问状态,通过两次入栈操作控制处理顺序[^1][^4]。 ```java public List<Integer> postOrderWithTag(TreeNode root) { List<Integer> result = new ArrayList<>(); if (root == null) return result; Stack<Object> stack = new Stack<>(); stack.push(root); while (!stack.isEmpty()) { Object obj = stack.pop(); if (obj instanceof TreeNode) { TreeNode node = (TreeNode) obj; stack.push(node.val); // 第一次弹出:节点值作为标记 stack.push(node.right); // 右子先处理 stack.push(node.left); // 左子后处理 } else { result.add((Integer) obj); } } return result; } ``` **步骤解析**(以二叉 `1 -> 2(),3()` 为例): 1. **初始状态**:栈中仅根节点`1` 2. **第一次弹出**:发现是`TreeNode`类型 - 将`1.val`、`1.right`、`1.left`按顺序压栈 → `stack=[1.val,3,2]` 3. **处理左子**: - 弹出`2`,再次压入`2.val`、`2.right`、`2.left` → `stack=[1.val,3,2.val,null,null]` 4. **处理叶子节点**: - 弹出`null`直接跳过 - 弹出`2.val`加入结果 → `result=[2]` 5. **处理右子**: - 弹出`3`,压入`3.val`、`3.right`、`3.left` → `stack=[1.val,3.val,null,null]` - 最终得到结果`2 → 3 → 1` --- #### 关键差异对比 | 方法 | 优势 | 缺点 | 适用场景 | |--------------|---------------------|------------------------|-------------------| | 双栈法 | 代码简洁,易理解 | 需要额外空间存储反向序列 | 结构简单时 | | 标记法 | 空间复杂度更低 | 类型转换增加复杂度 | 需要优化空间时 | --- #### 复杂度分析 - **时间复杂度**:$O(n)$,每个节点被访问两次(入栈出栈) - **空间复杂度**:$O(h)$,$h$为的高度,最坏情况下退化为$O(n)$ --- #### 相关问题 1. 为什么后序遍历非递归实现比先序/中序更难? 2. 如何用非递归方法实现二叉层次遍历? 3. 后序遍历在哪些算法中有重要应用?[^3] [^1]: 序/中序/后序非递归实现差异分析 : 中序遍历非递归实现参考 [^3]: 二叉遍历的拓展应用场景
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值