【leetcode】二叉树前、中、后序遍历
前序遍历
递归版本1
此解法比较简单,先访问 root 结点,然后用同样的方法递归去访问 root 结点的 left 结点然后是 root 结点的 right 结点,将他们放入容器vector中。注意这里使用了递归的方法,递归越深,内存开销越大:
class Solution {
public:
vector<int> ret;
vector<int> preorderTraversal(TreeNode* root) {
_prerder(root);
return ret;
}
void _prerder(TreeNode* root)
{
if (root)
{
ret.push_back(root->val);//访问其根节点
_prerder(root->left);//递归左子树
_prerder(root->right);//递归右子树
}
}
};
递归优化版本
同样也是先访问 root 结点,然后用同样的方法去访问 root 结点的 left 结点
然后是 root 结点的 right 结点,将他们放入容器vector中。在这里我使用了一个辅助函数 PushNode(), 该方法略微优化了一些,减少程序使用的内存
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
if (root) {
PushNode(root, result);
}
return result;
}
private:
void PushNode(TreeNode* root, vector<int> & v) {
if (root) {
v.push_back(root->val);
PushNode(root->left, v);
PushNode(root->right, v);
}
}
};
非递归实现
此种方法需要使用一个 stack 进行辅助,首先将 root 结点 push 到 栈中,然后就在一个 while 循环里去取栈的顶部,并将其保存。然后压栈 root 的right 结点,然后压栈 root 的 left 结点。注意:这里是前序遍历,所以先压栈 right 结点,是因为栈 LIFO(后进先出)的特点。直至 取完栈为空,可以清晰看出,内存消耗少了0.4MB。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> v;
if(root==NULL)
{
return v;
}
stack<TreeNode*> st;
TreeNode* tmp;
st.push(root);
while(!st.empty())
{
tmp=st.top();
v.push_back(tmp->val);
st.pop();
if(tmp->right!=NULL)
{
st.push(tmp->right);
}
if(tmp->left!=NULL)
{
st.push(tmp->left);
}
}
return v;
}
};
中序遍历
递归版本
此解法跟前序遍历一样,先递归访问 root 结点的left节点,然后去访问 root 结点,最后是 递归root 结点的 right 结点,将他们放入容器vector中。注意这里使用了递归的方法,递归越深,内存开销越大:
class Solution {
public:
vector<int> v;
vector<int> inorderTraversal(TreeNode* root) {
_inorderTraversal(root);
return v;
}
void _inorderTraversal(TreeNode* root)
{
if(root)
{
_inorderTraversal(root->left);
v.push_back(root->val);
_inorderTraversal(root->right);
}
}
};
非递归版本
思路:用while循环找最左路节点,并将沿路的节点push_back到栈中,然后将指针tmp指向的最左路节点放入容器vector中,然后pop掉,就退回到了自身指向的val上,放入容器vector中,然后再指向其右路节点,直到栈中为空结束。
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> v;
if (root == NULL)
{
return v;
}
stack<TreeNode*> st;
TreeNode* tmp = root;
while (tmp || st.size())
{
while (tmp)//一直找到最左边的节点,将所有左路节点,全部放入栈中
{
st.push(tmp);
tmp = tmp->left;
}
tmp = st.top();
st.pop();
v.push_back(tmp->val);
tmp = tmp->right;
}
return v;
}
};
后序遍历
递归版本
此解法和前序遍历一样,用同样的递归方法先去访问 root 结点的 left 结点,然后是 root 结点的 right 结点,最后访问 root 根结点,将他们放入容器vector中。注意这里使用了递归的方法, 递归越深,内存开销越大:
class Solution {
public:vector<int> v;
vector<int> postorderTraversal(TreeNode* root) {
_postorderTraversal(root);
return v;
}
void _postorderTraversal(TreeNode* root)
{
if (root)
{
_postorderTraversal(root->left);
_postorderTraversal(root->right);
v.push_back(root->val);
}
}
};
非递归版本
大致思路和前序遍历一样,就是最后把前序遍历倒过来输出就好了。
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> v,res;
if(root==NULL)
{
return v;
}
stack<TreeNode*> st;
TreeNode* tmp;
st.push(root);
while(!st.empty())
{
tmp=st.top();
v.push_back(tmp->val);
st.pop();
if(tmp->left!=NULL)
{
st.push(tmp->left);
}
if(tmp->right!=NULL)
{
st.push(tmp->right);
}
}
for(int i=v.size()-1;i>=0;--i)
{
res.push_back(v[i]);
}
return res;
}
};