【Leetcode】 94. 二叉树的中序遍历

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


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

示例 2

输入root = []
输出[]
示例 3

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

提示

cpp 复制代码
树中节点数目在范围 [0, 100] 内
-100 <= Node.val <= 100

进阶 : 递归算法 很简单,你可以通过迭代算法完成吗?


AC:

cpp 复制代码
/*
 * @lc app=leetcode.cn id=94 lang=cpp
 *
 * [94] 二叉树的中序遍历
 */

// @lc code=start
/**
 * 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 {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> st;
        TreeNode* cur = root;
        while(cur || !st.empty()) {
            if(cur) {
                st.push(cur);
                cur = cur->left;
            }
            else {
                cur = st.top();
                st.pop();
                res.push_back(cur->val);
                cur = cur->right;
            }
        }
        return res;
    }
};
// @lc code=end

着重谈一下 Morris 遍历
AC

cpp 复制代码
/*
 * @lc app=leetcode.cn id=94 lang=cpp
 *
 * [94] 二叉树的中序遍历
 */

// @lc code=start
/**
 * 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) {}
 * };
 */
/*
    Morris 遍历中,需要利用前驱节点指向当前节点的方式来遍历二叉树,
    算法的核心思想是将二叉树中每个节点的前驱节点的右孩子指向该节点,
    这样在遍历完当前节点的左子树后,
    可以通过前驱节点的右孩子指针找到该节点,
    并且不需要再次遍历该节点的左子树。遍历完成后,
    需要将前驱节点的右孩子指针重置为空。
*/
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
    // 定义结果数组和前驱节点指针
    vector<int> res;
    TreeNode *predecessor = nullptr;
    // 循环迭代直到遍历完整个二叉树
    while(root)
    {
        // 如果当前节点有左子节点,需要找到其左子树的最右侧节点作为前驱节点
        if(root->left)
        {
            // 找到前驱节点
            predecessor = root->left;
            while(predecessor->right && predecessor->right != root)
                predecessor = predecessor->right;
            // 如果前驱节点的右孩子为空,则将前驱节点的右孩子指向当前节点,然后遍历左子树
            if(predecessor->right == nullptr)
            {
                predecessor->right = root;
                root = root->left;
            }
            // 如果前驱节点的右孩子指向当前节点,说明左子树已经遍历完成,将前驱节点的右孩子置为空,并将当前节点加入结果数组,然后遍历右子树
            else{
                res.push_back(root->val);
                predecessor->right = nullptr;
                root = root->right;
            }
        }
        // 如果当前节点没有左子节点,则将当前节点加入结果数组,然后遍历右子树
        else{
            res.push_back(root->val);
            root = root->right;
        }
    }
    // 返回结果数组
    return res;
    }
};
// @lc code=end

Morris遍历是一种使用线索二叉树进行遍历的算法,它的空间复杂度O(1)。以下是C++代码实现:

前序遍历

cpp 复制代码
void morrisPreorderTraversal(TreeNode* root) {
    if (!root) return;
    TreeNode* cur = root, *predecessor = nullptr;
    while (cur) {
        if (!cur->left) {
            cout << cur->val << " ";
            cur = cur->right;
        }
        else {
            predecessor = cur->left;
            while (predecessor->right && predecessor->right != cur) {
                predecessor = predecessor->right;
            }
            if (!predecessor->right) {
                cout << cur->val << " ";
                predecessor->right = cur;
                cur = cur->left;
            }
            else {
                predecessor->right = nullptr;
                cur = cur->right;
            }
        }
    }
}

中序遍历:

cpp 复制代码
void morrisInorderTraversal(TreeNode* root) {
    if (!root) return;
    TreeNode* cur = root, *predecessor = nullptr;
    while (cur) {
        if (!cur->left) {
            cout << cur->val << " ";
            cur = cur->right;
        }
        else {
            predecessor = cur->left;
            while (predecessor->right && predecessor->right != cur) {
                predecessor = predecessor->right;
            }
            if (!predecessor->right) {
                predecessor->right = cur;
                cur = cur->left;
            }
            else {
                predecessor->right = nullptr;
                cout << cur->val << " ";
                cur = cur->right;
            }
        }
    }
}

后序遍历:

cpp 复制代码
vector<int> morrisPostorderTraversal(TreeNode* root) {
    if (!root) return {};
    vector<int> res;
    TreeNode* cur = root, *predecessor = nullptr;
    while (cur) {
        if (!cur->right) {
            res.push_back(cur->val);
            cur = cur->left;
        }
        else {
            predecessor = cur->right;
            while (predecessor->left && predecessor->left != cur) {
                predecessor = predecessor->left;
            }
            if (!predecessor->left) {
                res.push_back(cur->val);
                predecessor->left = cur;
                cur = cur->right;
            }
            else {
                predecessor->left = nullptr;
                cur = cur->left;
            }
        }
    }
    reverse(res.begin(), res.end());
    return res;
}
相关推荐
Jerry3 小时前
LeetCode 160. 相交链表
算法
Jerry3 小时前
LeetCode 19. 删除链表的倒数第 N 个结点
算法
金銀銅鐵3 小时前
费马小定理
python·数学·算法
技术不好的崎鸣同学4 小时前
[ACTF2020 新生赛]Exec 思路及解法
算法·安全·web安全
Full Stack Developme6 小时前
Java LRU 与 LFU 算法及应用
java·开发语言·算法
Jerry7 小时前
LeetCode 707. 设计链表
算法
C语言小火车7 小时前
C++ 堆排序深度精讲:基于完全二叉树的选择排序进化,最坏情况 O(n log n) 的稳定王者
开发语言·c++·算法·排序算法·堆排序
weixin_400005607 小时前
Vision-Language-Action:LMDrive双损失函数训练模块与 LangAuto 基准评测框架
人工智能·深度学习·算法·机器学习·自动驾驶
kebidaixu7 小时前
两轮BMS AFE SH367306 I2C 读写时序
算法