LeetCode145. 二叉树的后序遍历(递归和迭代的三种方法)

LeetCode145. 二叉树的后序遍历

1.问题

在这里插入图片描述

2.思路

(1)什么是后序遍历

在这里插入图片描述

(2)递归

和前序中序思路一样,只是将根结点放到最后访问

(3)迭代思路
a.改造先序遍历

在这里插入图片描述

b.仿造中根遍历

中根遍历:1.从根节点自上而下沿着左侧分支下行,并把沿途结点压栈,直到最深的结点(无左孩子)。
2.沿着左侧通道,自下而上弹栈,依次访问沿途各结点及其右子树

如下图所示:
在这里插入图片描述

而后序遍历面临一个问题: 弹栈后,不能马上访问p,而是要先访问p的右子树,然后访问p。所以需要以某种方式保存p。
策略1:不谈栈p,而是只取栈顶元素值。
策略2:允许结点多次进出栈,即弹栈p后让其马上再进栈。

策略1

在这里插入图片描述

策略2:

在栈元素里设置一个二元组,维护一个标号i,i代表当前结点进/出栈次数。 二叉树中任一结点p都要进栈三次,出栈三次。
第一次出栈是为遍历p的左子树。
第二次出战是为遍历p的右子树
第三次出栈是为了访问p。

在这里插入图片描述

在这里插入图片描述
运行实例
在这里插入图片描述伪代码
在这里插入图片描述

3.代码实现

(1)递归
class Solution
{
public:
    void posOrder(TreeNode*cur,vector<int>& vec)
    {
         if(cur == NULL)return;
        posOrder(cur->left,vec);//左
        posOrder(cur->right,vec);//右
        vec.push_back(cur->val);//根
    }

    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        posOrder(root, result);
        return result;
    }
};
(2)迭代
a.改造先序遍历
class Slution{
	public:
		vector<int> postorderTraversal(TreeNode* root) {
			stack<TreeNode*>st;
			vector<int> result;
			if(root == NULL) return result;
			st.push(root);
			while(!st.empty()){
				TreeNode* node = st.pop();
				st.pop();
				result.push_nack(node->val);
				if(node->left st.push(node->left));//相对于前序遍历这里做一下更改 
				if(node->right) st.push(node->right);//空节点不入栈 
			}
			reverse(result.begin(),result.end());//反转下结果就是左右中的顺序
			return result; 
		}
}; 
b.策略1
class Solution{
	public:
		vector<int> postorderTraversal(TreeNode* root) {
		stack<TreeNode*>st;
		vector<int> result;
		TreeNode* p = root; 
		TreeNode* pre = NULL;// pre是p的后根前驱,即在p之前访问的结点
		while(1){
			while(p!=NULL){
				st.push(p);
				p = p->left;
			}
			if(st.empty()) return result;
			p = st.top();
            if(p!=NULL){
            if( p->right == NULL||pre == p->right)
			{
				p = st.top();st.pop();
				result.push_back(p->val);
				pre = p; p = NULL;
			}
			else p = p->right;
		} 
        }
}
};
b.策略2

使用STL:

class Solution{
	public:
		vector<int> postorderTraversal(TreeNode* root) {
        int flag[512];
        int top = 0;//top指向即将放入元素的位置 这确实不好使 因为stl里没有改变top
        stack<TreeNode*>st;
		vector<int> result;
		flag[top] = 1;
		st.push(root);
        top++;
		while(!st.empty()){
			TreeNode* p = st.top();  
            st.pop();//出栈 
            top--;
			if(flag[top] == 1){
				flag[top] = 2; st.push(p); top++;
				if(p!= NULL && p->left != NULL) 
				{
					flag[top] = 1;
					st.push(p->left);
                    top++;
				}
			} 
			else if(flag[top] == 2)
			{
				flag[top] = 3; st.push(p);top++;
				if(p!=NULL && p->right != NULL){
					flag[top] = 1;
					st.push(p->right);
                    top++;
				}
			}
			else if(p!=NULL && flag[top] == 3)
				result.push_back(p->val);
		}
        return result;
}
};

注意!top得另外维护一下!stl里可没有int top这种东西!

不使用STL:

int flag[512];
int top = 0;//top指向即将放入元素的位置 
class stac{
public:
	void InitStack(){
		top = 0;
	}
	
	void Push(TreeNode *p){
		stack[top++] = p;
	}

    TreeNode* Pop(){
    	top--;
        return stack[top];
    }
	
	bool empty() {
  		if (top == 0)return true;
 		 return false;
    }
    
     TreeNode* Top( ){
        return stack[top-1];
 }
private:
	TreeNode *stack[512];
}; 

class Solution{
	public:
		vector<int> postorderTraversal(TreeNode* root) {
		stac st;
		st.InitStack();
		vector<int> result;
		flag[top] = 1;
		st.Push(root);
		while(!st.empty()){
			TreeNode* p = st.Pop();//出栈  
			if(flag[top] == 1){
				flag[top] = 2; st.Push(p);
				if(p!= NULL && p->left != NULL) 
				{
					flag[top] = 1;
					st.Push(p->left);
				}
			} 
			else if(flag[top] == 2)
			{
				flag[top] = 3; st.Push(p);
				if(p!=NULL && p->right != NULL){
					flag[top] = 1;
					st.Push(p->right);
				}
			}
			else if(p!=NULL && flag[top] == 3)
			{
				result.push_back(p->val);
			}	
            else
                continue;
		}
        return result;
}
};
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值