LeetCode145. 二叉树的后序遍历

本文介绍了如何对二叉树进行后序遍历,提供了递归和两种迭代方法的详细代码实现。递归方法直观简单,而迭代方法利用栈结构模拟递归过程,确保了正确顺序。两种迭代方法分别基于不同策略调整前序遍历顺序以达到后序遍历效果。
145. 二叉树的后序遍历


一、题目

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历

示例 1:

在这里插入图片描述

输入:root = [1,null,2,3]
输出:[3,2,1]

示例 2:

输入:root = []
输出:[]

示例 3:

输入:root = [1]
输出:[1]

提示:

  • 树中节点的数目在范围 [0, 100]
  • -100 <= Node.val <= 100

**进阶:**递归算法很简单,你可以通过迭代算法完成吗?

二、思路及代码
方法一:递归(比较简单)
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> v;
    vector<int> postorderTraversal(TreeNode* root) {
        if(root!=NULL){
            postorderTraversal(root->left);
            postorderTraversal(root->right);
            v.push_back(root->val);
        }
        return v;
    }
};
方法二:迭代(两种方法)

版本一

算法思路:

后序遍历的顺序是左子树、右子树、根节点。要实现后序遍历,可以使用栈的结构进行辅助。

  1. 初始化一个空栈和结果数组

  2. 将根节点入栈,并向左子树遍历

  3. 当左边遍历到头时,从栈顶取出节点,判断其右子树是否遍历过

    3.1 如果右子树未遍历,则将右子树作为根节点,向右子树遍历

    3.2 如果右子树已遍历或为空,则将这个节点放入结果数组中

  4. 重复上述操作,直到栈空为止

这样就可以通过栈的结构实现后序遍历的顺序。

具体实现:

  1. 定义栈和结果数组

  2. 当根节点或栈非空时循环

    2.1 将根节点入栈,遍历左子树

    2.2 从栈顶取出节点temp,判断其右子树

    2.3 如果右子树未遍历,则遍历右子树

    2.4 如果右子树已遍历,则将temp节点的值放入结果数组

  3. 返回结果数组

通过栈保存节点的顺序,模拟后序遍历的过程,从而实现后序遍历二叉树。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> result;
        TreeNode *prev = nullptr;
        while(root != NULL || !st.empty()){
            if(root != NULL){
                st.push(root);
                root = root->left;
            }
            else{
                TreeNode* temp = st.top();
                if(temp->right !=  NULL && temp->right != prev){
                    root = temp->right;
                }else{
                    result.push_back(temp->val);
                    st.pop();
                    prev = temp;
                }
                
            }
        }
        return result;
    }
};

算法分析:

  • 时间复杂度O(n):需要遍历所有节点
  • 空间复杂度O(n):栈的大小最大为n

版本2

算法思路:

这种方法的核心思路是,将前序遍历“根节点、左子树、右子树”的顺序改变为“根节点、右子树、左子树”,然后对结果反转,就可以得到后序遍历的顺序“左子树、右子树、根节点”。

具体来说:

  1. 初始化栈和结果数组

  2. 将根节点入栈

  3. 当栈非空时循环:

    3.1 从栈顶弹出节点p

    3.2 将p的值放入结果数组

    3.3 先将p的右子树入栈

    3.4 再将p的左子树入栈

  4. 反转结果数组

  5. 返回结果数组

通过修改前序遍历的顺序,并倒置结果,达到后序遍历的效果。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */

//本方法是前序遍历的变体,前序遍历是中左右,我们转换为中右左,最终倒序以后成为左右中
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> v;
        stack<TreeNode*>st;
        if(root==NULL){
            return v;
        }
        st.push(root);
        while(!st.empty()){
            TreeNode *p = st.top();
            st.pop();
            v.push_back(p->val);
            if(p->left)  st.push(p->left);
            if(p->right) st.push(p->right);       
        }
        reverse(v.begin(),v.end());//倒序
        return v;
    }
};

算法分析:

  • 时间复杂度 O(n):需要遍历所有节点
  • 空间复杂度 O(n):栈的大小最大为 n
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

KeepCoding♪Toby♪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值