返回

苦心 leetcode 94:二叉树中序遍历,别再执迷递归!

前端

二叉树中序遍历:递归、迭代和 Morris 三剑客

前言

在算法的世界中,leetcode 94 二叉树中序遍历是一个经典问题,考验着我们对树形结构和遍历算法的理解。传统上,我们习惯于使用递归来解决此题,但今天,我们将打破思维定式,深入探索迭代和 Morris 遍历的奥秘,带你领略算法之美的另一面。

递归解法:简单直接

思路:

递归是解决树形结构问题的经典方法。对于中序遍历,我们只需按照左-根-右的顺序依次遍历二叉树的子树即可。

public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> res = new ArrayList<>();
    helper(root, res);
    return res;
}

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

迭代解法:巧用栈

思路:

使用栈可以模拟递归的思想。我们只需将当前节点压入栈中,然后弹出栈顶元素并输出其值,再将弹出元素的右子树压入栈中,以此循环往复,直至栈空。

public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> res = new ArrayList<>();
    Stack<TreeNode> stack = new Stack<>();
    while (!stack.isEmpty() || root != null) {
        while (root != null) {
            stack.push(root);
            root = root.left;
        }
        root = stack.pop();
        res.add(root.val);
        root = root.right;
    }
    return res;
}

Morris 遍历:巧妙无需栈

思路:

Morris 遍历是一种巧妙的无栈遍历算法。它的关键在于利用二叉树的右指针,形成一个指向最左子节点的环形结构。然后,我们只需要沿环形结构移动即可实现中序遍历。

public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> res = new ArrayList<>();
    while (root != null) {
        TreeNode pre = root.left;
        if (pre == null) {
            res.add(root.val);
            root = root.right;
        } else {
            while (pre.right != null && pre.right != root) {
                pre = pre.right;
            }
            if (pre.right == null) {
                pre.right = root;
                root = root.left;
            } else {
                res.add(root.val);
                pre.right = null;
                root = root.right;
            }
        }
    }
    return res;
}

结语

leetcode 94 二叉树中序遍历看似简单,却蕴藏着算法思想的精髓。通过递归、迭代和 Morris 遍历三种方法的对比,我们不仅加深了对树形结构的理解,更领略到了算法设计的多样性和创造性。

常见问题解答

  1. 什么是二叉树的中序遍历?

答:中序遍历是一种遍历二叉树的算法,按照左-根-右的顺序输出二叉树中的节点值。

  1. 为什么使用递归来解决二叉树遍历问题?

答:递归是一种自然而然的方式来解决树形结构问题,因为树形结构本身具有递归的特性。

  1. 迭代解法比递归解法有什么优势?

答:迭代解法不需要调用函数,因此在内存使用和效率方面更优于递归解法。

  1. Morris 遍历和迭代解法的区别是什么?

答:迭代解法使用栈来模拟递归,而 Morris 遍历巧妙地利用二叉树的右指针,不需要使用栈。

  1. 在实际应用中,哪种遍历方法最常用?

答:递归解法简单易懂,在大多数情况下都是一个不错的选择。但如果需要处理大规模数据或在内存有限的环境中,迭代解法或 Morris 遍历可能是更好的选择。