94. Binary Tree Inorder Traversal
Given a binary tree, return the inorder traversal of its nodes' values.
Example:
Input: [1,null,2,3]
1
\
2
/
3
Output: [1,3,2]
Follow up: Recursive solution is trivial, could you do it iteratively?
题目链接:https://leetcode.com/problems/binary-tree-inorder-traversal/
题本身非常简单,写一个中序遍历二叉树的非迭代方法。主要问题就是平时迭代用多了,非迭代的方式不会写了。。
以下三种方法是二叉树遍历的常用方法
法一:迭代
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root){
vector<int> head;
inorder(root, head);
return head;
}
void inorder(TreeNode* root, vector<int> &head){
if(root != NULL){
inorder(root->left, head);
head.push_back(root->val);
inorder(root->right, head);
}
}
};
法二:非迭代+栈
此法就是将迭代方法的堆栈实现直接翻译出来。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> head;
stack<TreeNode*> pred;
TreeNode* curr = root;
while(curr != NULL || !pred.empty()){
if(curr != NULL){
pred.push(curr);
curr = curr -> left;
}else{
curr = pred.top();
pred.pop();
head.push_back(curr->val);
curr = curr -> right;
}
}
return head;
}
};
法三:Morris Traversal(运用线索二叉树)
Morris traversal的核心思想是,栈本身用来记录节点接下来该回退到哪个节点,那么我只用一个变量作为意义上的“栈”,用来记录这个节点即可。具体实现是改变了节点之间的指向关系,让原树结构变成一个链,一直输出没有左孩子的节点(没有左孩子就意味着在中序遍历中正好轮到输出它)。
算法步骤
1.初始化根节点root为当前节点curr。
2.while(curr is not NULL):
if(curr->left is NULL):
a) 输出curr的值;
b) curr = curr->right;
else:
a) 找到curr的左子树的最右叶子节点a,将curr移为a的右孩子,其他curr自身的指向关系不改变(相当于把根节点开始的右边一片树挪到了它左子树的最右);
b) 让curr回到它的左孩子后,再断开它们之间的指针,即curr = curr->left。
举个例子
原树长这样
1
/ \
2 3
/ \ /
4 5 6
第一个while之后变成了这样
2
/ \
4 5
\
1
\
3
/
6
最后得到的树就变成了
4
\
2
\
5
\
1
\
6
\
3
代码
vector<int> inorderTraversal(TreeNode* root){
vector<int> head;
TreeNode* curr = root;
TreeNode* pre;
while(curr != NULL){
if(curr->left == NULL){
head.push_back(curr->val);
curr = curr->right;
}
else{
pre = curr->left;
while(pre->right != NULL){
pre = pre->right;
}
pre->right = curr;
TreeNode* tmp = curr->left;
curr->left = NULL;
curr = tmp;
}
}
return head;
}
在复杂度上对比三种方法
方法 | 时间复杂度 | 空间复杂度 |
迭代 | O(n) | O(n) |
栈非迭代 | O(n) | O(n) |
Morris traversal | O(n) | O(1) |
延伸学习
1.关于二叉树的Morris traversal:https://blog.csdn.net/lemonade13/article/details/100084756
todo
复习下非迭代方法与迭代方法实现的相互转换
迭代的复杂度分析
c++堆栈的库常用函数总结
vecotr的常用函数