---
# System prepended metadata

title: 0094. Binary Tree Inorder Traversal
tags: [Leetcode, HashMap, Medium]

---

#  0094. Binary Tree Inorder Traversal
###### tags: `Leetcode` `Medium` `HashMap`
Link: https://leetcode.com/problems/binary-tree-inorder-traversal/
##  思路
这一题就是给一棵树，然后规定你读的顺序（先读左子树，再读root，再读右子树），然后按顺序把读到的东西印出来
### 方法一
递归
### 方法二
用一个stack来实现递归
### 方法三
**Morris 中序遍历**
Morris 遍历算法整体步骤如下（假设当前遍历到的节点为 x）：

如果 x 无左孩子，先将 x 的值加入答案数组，再访问 x 的右孩子，即 *x = x=x.right*。
如果 x 有左孩子，则找到 x 左子树上最右的节点（即左子树中序遍历的最后一个节点，x 在中序遍历中的前驱节点），我们记为 *predecessor*。根据 *predecessor* 的右孩子是否为空，进行如下操作。
如果 *predecessor* 的右孩子为空，则将其右孩子指向 x，然后访问 x 的左孩子，即 *x = x.left*。
如果 *predecessor* 的右孩子不为空，则此时其右孩子指向 x，说明我们已经遍历完 x 的左子树，我们将 *predecessor* 的右孩子置空，将 x 的值加入答案数组，然后访问 x 的右孩子，即 *x = x.right*。
重复上述操作，直至访问完整棵树。

其实整个过程我们就多做一步：假设当前遍历到的节点为 x，将 x 的左子树中最右边的节点的右孩子指向 x，这样在左子树遍历完成后我们通过这个指向走回了 x，且能通过这个指向知晓我们已经遍历完成了左子树，而不用再通过栈来维护，省去了栈的空间复杂度。

## Code
### 方法一
```c=
class Solution {
public:
    void inorder(TreeNode* root, vector<int>& ans){
        if(!root){
            return;
        }
        inorder(root->left, ans);
        ans.push_back(root->val);
        inorder(root->right, ans);
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ans;
        inorder(root, ans);
        return ans;
    }
};
```
### 方法二
```c=
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ans;
        stack<TreeNode*> stk;
        while(root!=nullptr || !stk.empty()){
            while(root!=nullptr){
                stk.push(root);
                root = root->left;
            }
            root = stk.top();
            stk.pop();
            ans.push_back(root->val);
            root = root->right;
        }
        return ans;
    }
};
```
### 方法三
**注意不能漏掉第二个while里面的predecessor->right ！= root的条件，否则会进入无限回圈**
eg: root在2处，找predecessor时，先往左走到4如果再往右走就会回到2。
![](https://i.imgur.com/ULVsRK2.png)

```c=
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ans;
        TreeNode *predecessor = nullptr;

        while (root != nullptr) {
            if (root->left != nullptr) {
                // predecessor 节点就是当前 root 节点向左走一步，然后一直向右走至无法走为止
                predecessor = root->left;
                while(predecessor->right != nullptr && predecessor->right != root){
                    predecessor = predecessor->right;
                }
                // 让 predecessor 的右指针指向 root，继续遍历左子树
                if (predecessor->right == nullptr) {
                    predecessor->right = root;
                    root = root->left;
                }
                // 说明左子树已经访问完了，我们需要断开链接
                else {
                    predecessor->right = nullptr;
                    ans.push_back(root->val);
                    root = root->right;
                }
            }
            // 如果没有左孩子，则直接访问右孩子
            else {
                ans.push_back(root->val);
                root = root->right;
            }
        }
        return ans;
    }
};

```
## Result
### 方法一
Runtime: 0 ms, faster than **100.00%** of C++ online submissions for Binary Tree Inorder Traversal.
Memory Usage: 8.2 MB, less than **82.50%** of C++ online submissions for Binary Tree Inorder Traversal.
### 方法二
Runtime: 0 ms, faster than **100.00%** of C++ online submissions for Binary Tree Inorder Traversal.
Memory Usage: 8.3 MB, less than **56.78%** of C++ online submissions for Binary Tree Inorder Traversal.
### 方法三
Runtime: 0 ms, faster than **100.00%** of C++ online submissions for Binary Tree Inorder Traversal.
Memory Usage: 8.3 MB, less than **82.50%** of C++ online submissions for Binary Tree Inorder Traversal.