一. 这题最直接的思路就是递归.
#include <iostream>
#include <vector>
using namespace std;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
//一定要设置全局变量的res.
//不然res不会改变.
vector<int> res;
vector<int> inorderTraversal(TreeNode* root) {
if (root == NULL)
return res;
res = inorderTraversal(root->left);
res.push_back(root->val);
res = inorderTraversal(root->right);
return res;
}
};
二. 但是这道题的重点是使用迭代算法.
三. 参考一下官方题解.
作者:LeetCode
链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/er-cha-shu-de-zhong-xu-bian-li-by-leetcode/
方法一:递归
1. 第一种解决方法是使用递归。这是经典的方法,直截了当。我们可以定义一个辅助函数来实现递归。
//方法一:递归
class Solution {
public:
//数组切记传入它的指针,否则不会跟着改变.
void helper(TreeNode* root, vector<int>& res) {
if (root == NULL)
return;
helper(root->left, res);
res.push_back(root->val);
helper(root->right, res);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
helper(root, res);
return res;
}
};
复杂度分析(可以参考算法递归树那一节)
1. 时间复杂度:O(n)。递归函数 T(n)=2⋅T(n/2)+1。(每个节点最多遍历两次,一次递, 一次归, 所以O(n)).
2. 空间复杂度:最坏情况下需要空间O(n)(退化成链表的时候),平均情况为O(logn)(递归树深度)。
方法二:基于栈的遍历
1. 本方法的策略与上方法很相似,区别是使用了栈。
//方法二:基于栈的遍历
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
//栈里存的是树的节点.
stack<TreeNode*> st;
while (root != NULL || !st.empty()) {
//一直循环,观察有无左子树.
while (root != NULL) {
st.push(root);
root = root->left;
}
root = st.top();
res.push_back(root->val);
st.pop();
root = root->right;
}
return res;
}
};
复杂度分析
-
时间复杂度:O(n)。
-
空间复杂度:O(n)。
四. 参考另一位大神的新颖方法.
作者:hzhu212
链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/yan-se-biao-ji-fa-yi-chong-tong-yong-qie-jian-ming/
2. 官方题解中介绍了三种方法来完成树的中序遍历,包括:递归 借助栈的迭代方法 莫里斯遍历
3. 在树的深度优先遍历中(包括前序、中序、后序遍历),递归方法最为直观易懂,但考虑到效率,我们通常不推荐使用递归。
4. 栈迭代方法虽然提高了效率,但其嵌套循环却非常烧脑,不易理解,容易造成“一看就懂,一写就废”的窘况。而且对于不同的遍历顺序(前序、中序、后序),循环结构差异很大,更增加了记忆负担。
5. 因此,我在这里介绍一种“颜色标记法”(瞎起的名字……),兼具栈迭代方法的高效,又像递归方法一样简洁易懂,更重要的是,这种方法对于前序、中序、后序遍历,能够写出完全一致的代码。
6. 其核心思想如下:
使用颜色标记节点的状态,新节点为白色,已访问的节点为灰色。
如果遇到的节点为白色,则将其标记为灰色,然后将其右子节点、自身、左子节点依次入栈。
如果遇到的节点为灰色,则将节点的值输出。
7. 这个方法很好,递归与非递归的记忆方法相同,只是顺序相反(只需要移动三句话的顺序)。如中序遍历:递归是左根右,非递归是右根左;先序遍历:左右根=》根右左。后序类似.
//大神的颜色标记法.
class Solution {
vector<int>ans;
public:
vector<int> inorderTraversal(TreeNode* root) {
int white = 0;
int gray = 1;
//pair与make_pair仔细学学.
stack<pair<int, TreeNode*>>s;
s.push(make_pair(white, root));
while (!s.empty()) {
int color = s.top().first;
TreeNode* t = s.top().second;
s.pop();
if (t == NULL) continue;
if (color == white) {
s.push(make_pair(white, t->right));
s.push(make_pair(gray, t));
s.push(make_pair(white, t->left));
}
else ans.push_back(t->val);
}
return ans;
}
};