LeetCode 94.二叉树的中序遍历 (C++)

题目地址:力扣

二叉树的中序遍历就是,左 -> 根 -> 右,这样的次序。

解法1:递归

class Solution {
public:
    // 递归体,遵循有左孩子进左孩子递归,没有则输出根,然后进右孩子递归
    void inorder(TreeNode *root, vector &res)
    {
        if (root == nullptr) {}
        else {
            if (root->left != nullptr)
                inorder(root->left, res);
            res.push_back(root->val);
            if (root->right != nullptr)
                inorder(root->right, res);
        }
            
    }
    
    // 外层方法,用于定义返回数组
    vector inorderTraversal(TreeNode* root) {
        vector res;
        inorder(root, res);
        return res;
    }
};

解法2:迭代,用栈来模拟递归调用的过程

class Solution {
public:
    vector inorderTraversal(TreeNode* root) {
        vector res;
        stack stk;
        // 只要根不为空和栈不为空二者满足其一
        while (root != nullptr || !stk.empty()) {
            // 若根不为空则一直将左孩子入栈,直到root为空
            while (root != nullptr) {
                stk.push(root);
                root = root->left;
            }
            // 弹栈并赋给root,结果加入res,栈里出来的元素只访问其右节点
            root = stk.top();
            stk.pop();
            res.push_back(root->val);
            // 这一步操作保证了下一轮循环开始的时候,root要么为空,要么为新的节点
            // 因此不会重复访问之前访问过的左孩子
            root = root->right;
        }
        return res;
    }
};

解法3:Morris遍历,这个比上面方法更高级,因为是迭代的方法而且不需要维护额外的栈。因为中序遍历的话我们需要一直深入到左子树底,这样就找不到最初的根节点了,因此这里的想法就是将二叉树改造为线索二叉树。由于根节点左子树中的最右下的节点一定是根节点中序遍历的前驱结点,因此只需要每往下找一层左子树的时候,将根节点赋给前驱结点的right即可,这样就可以找到根节点了。但是要注意的是,二叉树的遍历理论上不会改变二叉树结构,所以要保证遍历完之后所有前驱节点的right重新指向空才行,否则leetcode就会报stack over flow的问题。(排查了N久才发现的)

class Solution {
public:
    vector inorderTraversal(TreeNode* root) {
        vector res;
        TreeNode* pre = nullptr;

        while (root != nullptr)
        {
            if (root->left != nullptr)
            {
                // 这里的pre总是指向当前root节点为根中序遍历的前驱节点
                // 不管是在往下找的时候,还是往上回溯的时候
                // 往下找的时候利用pre添加线索,往上回溯的时候利用pre删除线索,保持树是原样的
                pre = root->left;
                // 往下的时候只需要保证pre没有右孩子即可,往上的时候保证右孩子不是root即可
                while (pre->right != nullptr && pre->right != root)
                    pre = pre->right;

                if (pre->right == nullptr)  // 说明还在向下过程中,该节点第一次遇到
                {
                    pre->right = root;
                    root = root->left;
                // 一定是向左探到最底了才会进入这个分支
                // 第一种情况是,不存在右子树,则断开前驱节点指向root的链,然后往上回溯
                // 第二种是中间节点存在右子树,则则断开前驱节点指向root的链,换到右子树进行探索
                } else {    
                    res.push_back(root->val);
                    pre->right = nullptr;
                    root = root->right;
                }
            }
            // 当前节点无左孩子,则往右探
            else {
                res.push_back(root->val);
                root = root->right;
            }
        }
        return res;
    }
};

Accepted

  • 70/70 cases passed (4 ms)
  • Your runtime beats 40.25 % of cpp submissions
  • Your memory usage beats 15.67 % of cpp submissions (8.2 MB)

你可能感兴趣的:(力扣刷题,leetcode,c++,算法)