【leetcode】---二叉树前、中、后序遍历

本文深入探讨二叉树的前序、中序和后序遍历算法,包括递归和非递归实现方式,详细解析每种遍历方法的步骤和特点,以及不同遍历方法在内存使用上的对比。

【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;
    }
};

在这里插入图片描述

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

L19002S

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值