二叉树的前序遍历、中序遍历、后序遍历

1. 递归法

1.1 前序遍历

class Solution {
    
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList();
        preOrder(root, list);
        return list;
    }      

    public void preOrder(TreeNode root, List list){
        if (root == null) {
            return;
        }
        list.add(root.val);
        preOrder(root.left, list);
        preOrder(root.right, list); 
    }  

}

1.2 中序遍历

// 递归解决  中序遍历:左中右
class Solution {
    public List<Integer> innerorderTraversal(TreeNode root) {

        List<Integer> list = new ArrayList();
        innerOrder(root, list);
        return list;
    }
    public void innerOrder(TreeNode root, List list) {
        if (root == null) {
            return;
        }
        // 左中右
        postOrder(root.left, list);
        list.add(root.val);
        postOrder(root.right, list);

    }
}

1.3 后序遍历

// 递归解决  中序遍历:左中右
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {

        List<Integer> list = new ArrayList();
        postOrder(root, list);
        return list;
    }
    public void postOrder(TreeNode root, List list) {
        if (root == null) {
            return;
        }
        // 左右中
        postOrder(root.left, list);
        postOrder(root.right, list);
        list.add(root.val);
    }
}

2. 迭代法

1.1 前序遍历

根 左 右

// 迭代法
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        // 创建list存储返回序列;创建stack用于前序遍历
        List<Integer> res = new ArrayList();
        Deque<TreeNode> stack = new LinkedList();
        TreeNode node = root;
        
        while(node != null || !stack.isEmpty()) {
        	// 因为先根,所以一直向左子树深入,根压栈,根加入res
            while(node != null) {
                stack.push(node);
                res.add(node.val);
                node = node.left;
            }
            // 没有左子树了,出栈判断右子树
            node = stack.pop();
            node = node.right;
        }
        return res;
    }
}

1.2 中序遍历

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>(); // 创建一个列表用于存储中序遍历结果
        Deque<TreeNode> stk = new LinkedList<TreeNode>(); // 创建一个双端队列(栈)用于辅助遍历
        
        while (root != null || !stk.isEmpty()) {
            // 遍历左子树并将节点入栈
            while (root != null) {
                stk.push(root);
                root = root.left;
            }
            
            // 当左子树遍历完后,弹出栈顶节点,将其值加入res列表
            root = stk.pop();
            res.add(root.val);
            
            // 遍历右子树
            root = root.right;
        }
        
        return res; // 返回中序遍历结果列表
    }
}

给定的代码使用了一个辅助栈来实现二叉树的中序遍历算法。以下是对代码的详细解释:

  1. inorderTraversal 方法接受一个名为 root 的 TreeNode 输入,并返回一个包含中序遍历结果的 List。
  2. 创建一个列表 res 用于存储中序遍历的结果。
  3. 创建一个双端队列(栈) stk 用于辅助遍历。
  4. 进入 while 循环,条件是当 root 不为空或者 stk 不为空时,即还有节点需要遍历。
  5. 在循环中,首先遍历左子树并将节点入栈,这一步将沿着树的左子树路径向下移动,并将经过的节点压入栈中。 当左子树遍历完毕时,执行下面的操作。
  6. 弹出栈顶节点,并将其值加入结果列表 res。 接着,将 root 指向当前节点的右子树,以便进行右子树的遍历。
  7. 循环继续,直到所有节点都被遍历。 最后,返回包含中序遍历结果的 res 列表。

该算法利用了栈的先进后出特性,通过遍历左子树并将节点压入栈中,然后弹出栈顶节点进行处理,再遍历右子树。通过不断地在左子树和右子树之间切换,最终完成了中序遍历。

1.3 后序遍历

class Solution {
    // 迭代实现二叉树的后序遍历
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode prev = null; // 用于判断当前根节点的右子树是否被完全遍历
        while(root != null || !stack.isEmpty()){
            while(root != null){
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            
            // 判断当前根节点的右子树是否被完全遍历
            if(root.right == null || root.right == prev){
                result.add(root.val); // 当右子树被完全遍历后,将当前根节点的值添加到结果列表中
                prev = root; // 更新 prev 为当前根节点
                root = null; // 将 root 置为空,以便向上回溯
            }
            else {
                stack.push(root); // 将当前根节点重新入栈
                root = root.right; // 遍历右子树
            }
        }
        return result; // 返回后序遍历结果列表
    }
}

其中,prev 变量用于帮助判断当前根节点的右子树是否被完全遍历过。

  1. postorderTraversal 方法接受一个名为 root 的 TreeNode 输入,并返回一个包含后序遍历结果的 List。

  2. 创建一个列表 result 用于存储后序遍历的结果。

  3. 创建一个栈 stack 用于辅助遍历。

  4. 创建一个变量 prev,用于判断当前根节点的右子树是否被完全遍历过。

  5. 进入 while 循环,条件是当 root 不为空或者 stack 不为空时,即还有节点需要遍历。

  6. 在循环中,首先遍历左子树并将节点入栈,这一步将沿着树的左子树路径向下移动,并将经过的节点压入栈中。

  7. 当左子树遍历完毕时,执行下面的操作。

  8. 弹出栈顶节点,并将其赋值给 root。

  9. 使用条件判断语句,判断当前根节点的右子树是否被完全遍历过。如果满足以下条件之一,表示当前根节点的右子树已经被完全遍历过:

  • 右子树为空:root.right == null
  • 右子树是上一个遍历的节点(prev):root.right == prev
  1. 如果满足上述条件,将当前根节点的值加入结果列表 result,并更新 prev 为当前根节点。

  2. 将 root 置为空,以便在下一次循环中向上回溯。

  3. 如果当前根节点的右子树未被完全遍历,将当前根节点重新入栈,然后将 root 指向当前节点的右子树,以便进行右子树的遍历。

  4. 循环继续,直到所有节点都被遍历。

  5. 最后,返回包含后序遍历结果的 result 列表。

prev 变量的作用是为了判断当前根节点的右子树是否被完全遍历过。在后序遍历中,我们需要先遍历左子树、再遍历右子树,最后才访问根节点。当右子树被完全遍历后,我们才能将根节点加入到结果列表中。通过使用 prev 变量,我们可以判断当前根节点的右子树是否已经被遍历完,如果是,则可以将根节点加入结果列表中。然后,我们将 prev 更新为当前根节点,继续向上回溯。这样可以确保在遍历完右子树后,才将根节点添加到结果列表中,符合后序遍历的要求。

重新入栈,prev更新,node设为null 是关键

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值