【力扣hot100】94. 二叉树的中序遍历(递归/迭代)

一、题目

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

示例 1:

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

示例 2:
输入:root = []
输出:[]

示例 3:
输入:root = [1]
输出:[1]
 
提示:
树中节点数目在范围 [0, 100] 内
-100 <= Node.val <= 100

二、思路

如果做过hot100中538那题,这题估计5分钟就做完了。就是普通的中序遍历,左根右,先把左节点放进去,然后把自己放进去,最后右边,递归一下就行了

三、代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
private:
    vector<int> sort;
public:
    void inorder(TreeNode* root){
        if(root==NULL){
            return;
        }
        inorderTraversal(root->left);
        sort.push_back(root->val);
        inorderTraversal(root->right);
    }
    vector<int> inorderTraversal(TreeNode* root) {
        inorder(root);
        return sort;
    }
};

四、进阶

在题目下面有注意到用迭代算法解决,但我之前没怎么接触过,先给出两者区别:

递归是函数反复调用自己去解决更小的问题,直至达成结束条件

迭代是用循环(for,while等)重复操作,在不自调用的情况下解决问题

我直接搬来了官方题解,来根据这个分析一下。简单来说就是显式的维护了一个节点栈,通过不断向左深入搜索往栈内存放父节点,触底时挨个取出父节点,再向右搜索

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> stk;
        while (root != nullptr || !stk.empty()) {    //节点为空,或,栈里还有未处理节点,则继续循环
            while (root != nullptr) {    //当节点不为空时
                stk.push(root);          //为之后由子节点返回父节点保留
                root = root->left;       //一直向左节点深入搜索
            }
            root = stk.top();    //当节点为空时,root=最近的父节点
            stk.pop();           //由于root已经变为父节点,故pop
            res.push_back(root->val);    //将父节点的值加入res
            root = root->right;    //继续搜右边
        }
        return res;
    }
};

### 力扣二叉树序遍历的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 实现方案用于解决力扣上的二叉树序遍历问题。每种方法各有优劣,在实际应用中可以根据需求灵活选用合适的策略。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值