力扣-数据结构-二叉树

94. 二叉树的中序遍历

给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

示例 1:

输入:root = [1,null,2,3]
输出:[1,3,2]

示例 2:

输入:root = []
输出:[]

示例 3:

输入:root = [1]
输出:[1]

方法一:递归实现(最简单)

# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def inorderTraversal(self, root: TreeNode) -> list[int]:
        result = []

        def dfs(node):
            if not node:
                return
            dfs(node.left)
            result.append(node.val)
            dfs(node.right)

        dfs(root)
        return result

方法二:迭代实现(使用栈)

class Solution:
    def inorderTraversal(self, root: TreeNode) -> list[int]:
        result = []
        stack = []
        current = root

        while current or stack:
            while current:
                stack.append(current)
                current = current.left  # 一直往左走
            current = stack.pop()
            result.append(current.val)
            current = current.right  # 然后往右走

        return result

### 力扣二叉树中序遍历的Java实现思路 #### 方法一:递归解法 递归是一种直观且易于理解的方法。通过定义一个辅助函数 `dfs`,按照 **左子树 -> 根节点 -> 右子树** 的顺序依次处理每个节点。对于每一个节点,如果它不为空,则先递归遍历其左子树,接着将该节点的值加入结果列表,最后递归遍历右子树。 以下是具体的代码实现: ```java class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> res = new ArrayList<>(); dfs(res, root); return res; } private void dfs(List<Integer> res, TreeNode node) { if (node == null) { return; } dfs(res, node.left); // 递归遍历左子树 res.add(node.val); // 访问根节点 dfs(res, node.right); // 递归遍历右子树 } } ``` 这种方法的时间复杂度和空间复杂度均为 O(n),其中 n 是二叉树中的节点数[^3]。 --- #### 方法二:迭代解法 迭代方法的核心思想是手动模拟递归过程中使用的栈结构。由于递归本质上也是利用系统栈完成操作,因此可以通过显式的栈来替代系统的隐式调用栈。 具体步骤如下: 1. 初始化一个空的结果列表 `res` 和一个栈 `stack`。 2. 使用一个指针变量 `current` 指向当前正在访问的节点。 3. 当前节点不为空或栈不为空时进入循环: - 如果当前节点存在,将其压入栈并继续移动到它的左子节点; - 否则弹出栈顶元素(即最近一次未完全访问的节点),记录其值,并转向其右子节点。 4. 循环结束后返回结果列表。 下面是对应的代码实现: ```java class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> res = new ArrayList<>(); Deque<TreeNode> stack = new LinkedList<>(); TreeNode current = root; while (current != null || !stack.isEmpty()) { while (current != null) { // 将所有左子节点压入栈 stack.push(current); current = current.left; } current = stack.pop(); // 弹出栈顶元素 res.add(current.val); // 添加到结果集 current = current.right; // 移动至右子节点 } return res; } } ``` 此方法同样具备时间复杂度 O(n)[^2] 和最坏情况下空间复杂度也为 O(n) 的特性。 --- #### 方法三:Morris 遍历 Morris 遍历是一种不需要额外存储空间的高效算法,其核心思想是在遍历时修改树的结构以建立临时链接,从而避免使用栈或递归来保存中间状态。最终恢复原始树形结构的同时完成了遍历。 主要逻辑分为以下几个部分: 1. 初始设置当前节点为根节点。 2. 对于每个节点,判断是否有左子树: - 若无左子树,则直接访问该节点并将指针移向右子树; - 若有左子树,则找到左子树中最右侧的节点(即前驱节点)并与当前节点连接起来;随后再次调整指针位置。 3. 继续上述过程直至整棵树被完整遍历完毕。 以下是 Morris 遍历的具体实现: ```java class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> res = new ArrayList<>(); TreeNode current = root; while (current != null) { if (current.left == null) { // 左子树不存在 res.add(current.val); // 直接访问当前节点 current = current.right; // 转移到右子树 } else { // 存在左子树 TreeNode predecessor = findPredecessor(current); if (predecessor.right == null) { // 前驱尚未连接回当前节点 predecessor.right = current; // 创建反向链路 current = current.left; // 进入左子树 } else { // 前驱已连接回来 predecessor.right = null; // 断开反向链路 res.add(current.val); // 访问当前节点 current = current.right; // 转移到右子树 } } } return res; } private TreeNode findPredecessor(TreeNode node) { TreeNode pred = node.left; while (pred.right != null && pred.right != node) { pred = pred.right; } return pred; } } ``` 这种做法的空间复杂度仅为 O(1)[^4],因为除了输入数据外无需任何附加内存支持。 --- ### 总结 以上介绍了三种不同的 Java 实现方案用于解决力扣上的二叉树中序遍历问题。每种方法各有优劣,在实际应用中可以根据需求灵活选用合适的策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值