用栈实现二叉树的前、中、后序遍历学习笔记(leetcode94\144\145)

前言

前面学习了递归实现二叉树的方法,而递归的定义就是: 每一次递归调用,都会把函数的局部变量、参数值和返回地址等压入调用栈中。 然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。
那么,可以用非递归的方式实现吗? 答案是可以。
所以,用栈(非递归的方式)可以实现二叉树的前中后序遍历。

前序遍历

这里引用一下大佬的动图,来总结一下前序遍历的规律
在这里插入图片描述
以上用例的前序遍历是:5、4、1、2、6 (中、左、右)
在入栈时, ①先读取根节点,取值,然后直接将根节点出栈。 ②读取右节点、再读取左节点 ,取值,出栈
因为要考虑出栈顺序,符合前序遍历。所以入栈顺序是中、右、左。
代码如下:

	class Solution {
	public:
	    vector<int> preorderTraversal(TreeNode* root) {
	        stack<TreeNode*> st;//1、建栈
	        vector<int> result;//2、存前序遍历结果
	        st.push(root);//读根节点,用push
	        while (!st.empty()) {
	        	//根节点不为空,入栈
	            TreeNode* node = st.top();                      // 中
	            st.pop();
	            //根节点不为空,存入前序遍历中
	            //ps: 对象存元素,用.      指针访问元素,用->
	            if (node != NULL) result.push_back(node->val);
	            //为空就走下一个节点元素
	            else continue;
	            //规定下一个节点元素是什么
	            st.push(node->right);                           // 右
	            st.push(node->left);                            // 左
	        }
	        return result;
	    }
	};

中序遍历

写中序遍历的时候,就不能上面的代码了。
因为,前序遍历时,先要处理的元素,和先要访问的元素,顺序都是一致的,都是中间节点。
而中序遍历是(左、中、右)跟入栈的顺序完全相反。
所以, 这时候要借助指针的遍历,帮助访问节点。而栈用来处理节点上的元素。
这里引用一下大佬的动图,来总结一下中序遍历的规律
在这里插入图片描述
以上用例的中序遍历是:1、4、2、5、6 (左、中、右)
在入栈时, ①用node指针一直访问到二叉树左子树为空的时候,每成功访问一课左子树,就入栈 ②当左子树为空,栈不为空时,说明要开始中序遍历:栈顶值给当前指针,出栈,访问右子树。依此循环
代码如下:

	class Solution {
	public:
	    vector<int> inorderTraversal(TreeNode* root) {
	        stack<TreeNode*> s1;//栈
	        TreeNode* node;
	        node = root;//根节点
	        vector<int> result;//存中序遍历
	        //栈不为空,存在根节点
	        //node不为空,存在根节点下的右子树
	        while(!s1.empty() || node!=nullptr){
	            //1、没达到左子树底端
	            if(node!=nullptr){
	                s1.push(node);//2、先入栈
	                node =node->left;//3、接着访问左子树
	            }else{
	                node = s1.top();//取栈顶
	                result.push_back(node->val);//存元素
	                s1.pop();//出栈
	                node=node->right;//寻找右子树
	            }
	        }
	        return result;
	    }
	};

后序遍历

后续遍历是左右中。
那么我们只需要:
①调整一下先序遍历的代码顺序,就变成中右左的遍历顺序。
②然后在反转result数组,输出的结果顺序就是左右中了。
如下图:
在这里插入图片描述
前序遍历代码一改,美滋滋。

	class Solution {
	public:
	    vector<int> postorderTraversal(TreeNode* root) {
	        stack<TreeNode*> s1;//只能读节点
	        vector<int> result;
	        TreeNode* node;
	        s1.push(root);
	        while(!s1.empty()){
	            node =s1.top();
	            s1.pop();
	            if(node!=NULL){
	              result.push_back(node->val);   
	                 s1.push(node->left);
	                s1.push(node->right);
	            }else
	                continue;
	            // s1.push(node->left);  魔改的前序,效果都是一样的
	            // s1.push(node->right);
	        }
	        reverse(result.begin(),result.end());//将魔改的前序反转了
	        return result;
	    }
	};

参考文献

二叉树:听说递归能做的,栈也能做!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

晓梦林

都看到这里了,支持一下作者呗~

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

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

打赏作者

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

抵扣说明:

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

余额充值