题目地址:
https://leetcode.com/problems/binary-tree-inorder-traversal/
中序遍历二叉树。
法1:DFS。代码如下:
/**
* 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;
dfs(root, res);
return res;
}
void dfs(TreeNode* p, vector<int>& res) {
if (!p) return;
dfs(p->left, res);
res.push_back(p->val);
dfs(p->right, res);
}
};
时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( h ) O(h) O(h)。
法2:用栈模拟递归。递归的过程是,从树根开始一路向左,同时记录住一路经过的节点,直到向左走到null后回退一步,打印节点,接着向其右子树拐过去,继续重复一路向左,直到右子树遍历完后,回退到树根的上一个节点,打印之,再拐入右子树继续重复。所以用栈来模拟的话就是,先从树根出发一路向左,同时将路径上所有节点按顺序入栈,直到走到null,走到null后,栈里弹出来一个节点就可以访问之了,因为其左子树是空。访问完后向右拐,如果右子树不空就继续上面一路向左的过程;否则就将栈里继续弹出一个节点并访问,然后继续向右拐重复上面的操作。代码如下:
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> stk;
auto cur = root;
while (cur || stk.size()) {
// 将左链入栈
while (cur) {
stk.push(cur);
cur = cur->left;
}
// 存一下栈顶
cur = stk.top();
stk.pop();
res.push_back(cur->val);
// 拐到右边继续遍历
cur = cur->right;
}
return res;
}
};
时空复杂度一样。
法3:Morris遍历。这种遍历是空间 O ( 1 ) O(1) O(1)的二叉树遍历法。过程如下:
- 开个指针存树根,从树根出发;
- 如果没有左儿子,则存当前节点,然后向右走;
- 如果有左儿子,则找当前节点前驱,如果前驱和当前节点未相连,则连起来,然后向左走;如果已经与当前节点相连,则拆桥,存当前节点,然后向右走。
概括起来就是:树根出发,无前驱就向右走,有前驱则找前驱,前驱无桥则搭桥向左走,前驱有桥则拆桥向右走。
代码如下:
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
auto cur = root;
while (cur) {
if (!cur->left) {
res.push_back(cur->val);
cur = cur->right;
continue;
}
auto left = cur->left;
while (left->right && left->right != cur) left = left->right;
if (!left->right) {
left->right = cur;
cur = cur->left;
} else {
left->right = nullptr;
res.push_back(cur->val);
cur = cur->right;
}
}
return res;
}
};
时间复杂度 O ( n ) O(n) O(n),空间 O ( 1 ) O(1) O(1)。