Problem
Solution
给定一棵二叉树,输出其先序(preorder)遍历结果。
想法有三
第一种,递归版本。因为二叉树的遍历定义其实就是一种递归形式的定义,因此很好想到对应代码。但是递归有一个问题,产生的空间复杂度比较高,因为系统栈每次都会把所有变量都临时保存,会产生很多的重复。
/**
* 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> ans;
vector<int> preorderTraversal(TreeNode* root) {
if(root==NULL) return ans;
ans.push_back(root->val);
preorderTraversal(root->left);
preorderTraversal(root->right);
return ans;
}
};
第二种,把递归改成迭代,可以减小时间、空间复杂度的常系数。因为先序遍历的递归十分类似于尾递归,那么我们可以用消除尾递归的方法直接改写成遍历版本1。这个遍历版本其实就是模拟了递归版本的系统堆栈的工作过程。
/**
* 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> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> ans;
if(root) st.push(root);
while(!st.empty()){
TreeNode* p=st.top();
st.pop();
ans.push_back(p->val);
if(p->right) st.push(p->right);
if(p->left) st.push(p->left);
}
return ans;
}
};
第三种,众所周知,二叉树的遍历除了preorder,还有inorder、postorder。preorder的递归版本可以看成尾递归,但是另外两种的递归版本(也很好写,只是改变一下访问值语句的位置就可以了)就无法根据尾递归消除的规则来改写成迭代版本了。
这时我们必须换种思路,通过下图,我们可以总结出先序遍历的一种方法,先沿着左边自顶向下访问左边节点,然后再自底向下遍历这些节点的右子树。若某节点右子树不存在为空,则继续返回到上一个节点再看右子树是否存在;若某节点右子树存在,那么对该右子树也是同样的遍历规则,先访问最左边的那些节点…(重复上述过程)。该思想可以在inorder、postorder也有用武之地。
/**
* 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:
void visitleft(TreeNode *x,stack<TreeNode*> &st,vector<int> &ans){
while(x)
{
ans.push_back(x->val);
st.push(x->right);
x=x->left;
}
return;
}
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> ans;
TreeNode *p=root;
while(true)
{
visitleft(p,st,ans);
if(st.empty()) break;
p=st.top();
st.pop();
}
return ans;
}
};