gh_mirrors/leet/leetcode项目:二叉树的中序遍历题解

gh_mirrors/leet/leetcode项目:二叉树的中序遍历题解

【免费下载链接】leetcode LeetCode题解,151道题完整版。广告:推荐刷题网站 https://www.lintcode.com/?utm_source=soulmachine 【免费下载链接】leetcode 项目地址: https://gitcode.com/gh_mirrors/leet/leetcode

你是否在面对二叉树中序遍历时感到困惑?是否还在用递归方法却担心栈溢出问题?本文将带你深入理解二叉树的中序遍历(Inorder Traversal),从基础概念到两种高效实现方法,让你轻松掌握这一必备算法技能。读完本文后,你将能够:

  • 清晰理解中序遍历的访问顺序和应用场景
  • 掌握栈实现的迭代解法,避免递归限制
  • 学会O(1)空间复杂度的Morris遍历算法
  • 能够独立解决LeetCode相关题目

什么是二叉树的中序遍历

二叉树的中序遍历(Inorder Traversal)是按照"左子树→根节点→右子树"的顺序访问树中所有节点的过程。对于二叉搜索树(BST)而言,中序遍历的结果是一个有序序列,这一特性使其在解决BST相关问题时具有重要应用。

树的节点定义在C++/chapTree.tex中给出:

// 树的节点
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) { }
};

以下面的二叉树为例:

  1
   \
    2
   /
  3

中序遍历的结果是[1,3,2],即先访问左子树(为空),再访问根节点1,然后访问右子树的左节点3,最后访问右子树的根节点2。

栈实现的迭代解法

递归实现虽然简洁,但在处理大型树时可能会遇到栈溢出问题。使用显式栈的迭代方法可以有效避免这一问题,时间复杂度O(n),空间复杂度O(n)。

C++/chapTree.tex中提供了完整实现:

// LeetCode, Binary Tree Inorder Traversal
// 使用栈,时间复杂度O(n),空间复杂度O(n)
class Solution {
public:
    vector<int> inorderTraversal(TreeNode *root) {
        vector<int> result;
        stack<const TreeNode *> s;
        const TreeNode *p = root;

        while (!s.empty() || p != nullptr) {
            if (p != nullptr) {
                s.push(p);
                p = p->left;
            } else {
                p = s.top();
                s.pop();
                result.push_back(p->val);
                p = p->right;
            }
        }
        return result;
    }
};

算法步骤解析

  1. 初始化一个空栈和结果向量
  2. 从根节点开始,将所有左孩子依次入栈,直到左子树为空
  3. 弹出栈顶节点,将其值加入结果向量
  4. 转向该节点的右子树,重复步骤2-3
  5. 直到栈为空且当前节点也为空时结束

下面的流程图展示了这一过程:

mermaid

Morris中序遍历:O(1)空间复杂度解法

Morris遍历算法通过利用树的空闲指针(线索化),实现了不需要栈的中序遍历,将空间复杂度降至O(1)。这一算法在C++/chapTree.tex中有详细实现:

// LeetCode, Binary Tree Inorder Traversal
// Morris中序遍历,时间复杂度O(n),空间复杂度O(1)
class Solution {
public:
    vector<int> inorderTraversal(TreeNode *root) {
        vector<int> result;
        TreeNode *cur = root, *prev = nullptr;

        while (cur != nullptr) {
            if (cur->left == nullptr) {
                result.push_back(cur->val);
                prev = cur;
                cur = cur->right;
            } else {
                /* 查找前驱 */
                TreeNode *node = cur->left;
                while (node->right != nullptr && node->right != cur)
                    node = node->right;

                if (node->right == nullptr) { /* 还没线索化,则建立线索 */
                    node->right = cur;
                    /* prev = cur; 不能有这句,cur还没有被访问 */
                    cur = cur->left;
                } else {    /* 已经线索化,则访问节点,并删除线索  */
                    result.push_back(cur->val);
                    node->right = nullptr;
                    prev = cur;
                    cur = cur->right;
                }
            }
        }
        return result;
    }
};

算法核心思想

Morris算法的关键在于为每个节点寻找其前驱节点,并利用前驱节点的右指针暂时存储后继节点信息,避免使用栈。主要步骤包括:

  1. 如果当前节点左子树为空,访问该节点并转向右子树
  2. 否则,找到当前节点在中序遍历中的前驱节点(左子树的最右节点)
  3. 如果前驱节点右指针为空,将其指向当前节点,然后转向当前节点的左子树
  4. 如果前驱节点右指针已指向当前节点,说明左子树已遍历完成,访问当前节点并将前驱右指针复位,然后转向当前节点的右子树

两种方法的对比分析

实现方法时间复杂度空间复杂度优点缺点
栈迭代法O(n)O(n)实现直观,易于理解需要额外栈空间,可能栈溢出
Morris遍历O(n)O(1)空间效率极高实现复杂,修改树结构(临时)

实际应用与相关题目

中序遍历在二叉搜索树(BST)中有重要应用,例如验证BST的合法性、寻找BST中的第K小元素等。在本项目中,相关题目可以在C++/chapTree.tex中找到:

  • Binary Tree Preorder Traversal
  • Binary Tree Postorder Traversal
  • Recover Binary Search Tree

以"恢复二叉搜索树"题目为例,中序遍历可以帮助我们找到被错误交换的节点,这展示了中序遍历在实际问题中的重要性。

总结与展望

二叉树的中序遍历是数据结构中的基础算法,本文详细介绍了两种主流实现方法:栈迭代法和Morris遍历法。栈迭代法简单直观,适合大多数情况;而Morris法则在空间受限场景下提供了优秀的解决方案。

建议初学者先掌握栈迭代法,理解中序遍历的本质;进阶学习者则应掌握Morris算法,理解其线索化思想,这对解决复杂树问题大有裨益。

更多二叉树相关题解,请参考项目中的C++/chapTree.tex文件,其中包含了先序、后序、层序等多种遍历方法的实现。

最后,推荐使用项目描述中提到的刷题网站进行练习,巩固所学知识:https://www.lintcode.com/?utm_source=soulmachine

【免费下载链接】leetcode LeetCode题解,151道题完整版。广告:推荐刷题网站 https://www.lintcode.com/?utm_source=soulmachine 【免费下载链接】leetcode 项目地址: https://gitcode.com/gh_mirrors/leet/leetcode

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值