【LeetCode】二叉树的后序遍历(递归,迭代)

news/2025/1/13 7:52:48/

目录

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

方法一:递归

方法二:迭代

思路分析:

代码展示:

复杂度分析

方法三:迭代进阶

思路分析:

代码展示:


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

示例 1:

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

 

方法一:递归

递归的方法和二叉树的前序以及中序遍历在之前的博客中已经写过,需要的小伙伴可以点击链接查看

递归求二叉树的前中后序遍历

【LeetCode】二叉树的前序遍历(递归,迭代,Morris遍历)

【LeetCode】二叉树的中序遍历(递归,迭代,Morris遍历)

这篇文章主要来讲解非递归的方法对二叉树进行后序遍历

方法二:迭代

思路分析:


迭代的方式其实与递归是等价的,区别在于递归的时候隐式地维护了一个栈,而我们在迭代的时候

需要显式地将这个栈模拟出来,其余的实现与细节都相同,具体可以参考下面的代码

其实后序遍历的思想与中序遍历大差不差,只不过中序是左根右,在栈中弹出的元素其左子树都是已访问完的,此时我们可以直接访问该节点,再继续访问它的右子树就是了

后续遍历是左右根,此时我们只能保证该节点的左子树访问完成,但却不知晓右子树的情况,此时我们只需维护一个节点,用来帮助我们判断该节点的右子树有没有被访问过即可

代码展示:

class Solution {public List<Integer> postorderTraversal(TreeNode root) {//栈和线性表List<Integer> list = new ArrayList<>();if(root == null){return list;}Deque<TreeNode> stack = new LinkedList<>();TreeNode prev = null;while(root != null || !stack.isEmpty()){//root非空while(root != null){stack.push(root);root = root.left;}//此时root为空,我们需要判断右子树是否走过或者为空root = stack.pop();if(root.right == null || root.right == prev){list.add(root.val);prev = root;root = null;}else{stack.push(root);root = root.right;}}return list;}
}

复杂度分析

  • 时间复杂度:O(n),其中 n 是二叉树的节点数。每一个节点恰好被遍历一次。

  • 空间复杂度:O(n),为迭代过程中显式栈的开销,平均情况下为 O(log⁡n),最坏情况下树呈现链状,为 O(n)

方法三:迭代进阶

思路分析:

我们都知道前序遍历与后序遍历的差别就是根的位置的关系

前序遍历顺序为:根 -> 左 -> 右

后序遍历顺序为:左 -> 右 -> 根

如果我们用链表来存储节点,并且改为头插的方式,那么按照前序遍历的结果

链表就变为了:右 -> 左 -> 根

我们将遍历的顺序由从左到右修改为从右到左

结果链表就变为了:左 -> 右 -> 根,这刚好就是后序遍历的结果

代码展示:

class Solution {public List<Integer> postorderTraversal(TreeNode root) {List<Integer> list = new ArrayList<>();if(root == null){return list;}Deque<TreeNode> stack = new LinkedList<>();stack.push(root);while(!stack.isEmpty()){TreeNode x = stack.pop();list.add(0,x.val);if(x.right != null){stack.push(x.right);}if(x.left != null){stack.push(x.left);}}return list;}
}


http://www.ppmy.cn/news/35532.html

相关文章

7.网络爬虫—正则表达式详讲

7.网络爬虫—正则表达式详讲与实战Python 正则表达式re.match() 函数re.search方法re.match与re.search的区别re.compile 函数检索和替换检索&#xff1a;替换&#xff1a;findallre.finditerre.split正则表达式模式常见的字符类正则模式正则表达式模式量词正则表达式举例前言&…

【C++进阶】智能指针

文章目录为什么需要智能指针&#xff1f;内存泄漏什么是内存泄漏&#xff0c;内存泄漏的危害内存泄漏分类&#xff08;了解&#xff09;如何避免内存泄漏智能指针的使用及原理smart_ptrauto_ptrunique_ptrshared_ptr线程安全的解决循环引用weak_ptr删除器为什么需要智能指针&am…

2020年第十一届C/C++ B组第一场蓝桥杯省赛真题

准备参加第十四届蓝桥杯&#xff0c;今天开始刷题目的第一天&#xff0c;下面是2020年第十一届C/C B组第一场蓝桥杯省赛真题&#xff0c;以下是我的做题目心得。跑步训练第一次写的代码失误点如下&#xff1a;第一个错误点是因为好久没有写代码&#xff0c;忘记判断对才能循环&…

【C语言蓝桥杯每日一题】—— 货物摆放

【C语言蓝桥杯每日一题】—— 货物摆放&#x1f60e;前言&#x1f64c;排序&#x1f64c;总结撒花&#x1f49e;&#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭&#xff1a;全神贯注的上吧&#xff01;&#xff01;&#xff01; &#x1f60a;作者简介…

C 语言网络编程 — 内核协议栈收包/发包流程

目录 文章目录目录关键技术DMAsk_buff 结构体Net driver Rx/Tx Ring BufferBuffer Descriptor TableNAPI 收包机制网卡多队列内核协议栈收包/发包流程概览内核协议栈收包流程详解驱动程序层&#xff08;数据链路层&#xff09;VLAN 协议族Linux Bridge 子系统网络协议层&#x…

PWM互补输出,以及死区时间计算

本文基于野火例程进行解说 实验内容 本次实验输出一对互补的pwm波&#xff0c;且进行死区时间的计算说明。 代码 互补输出对应的定时器初始化代码&#xff1a; bsp_advance_tim.c /********************************************************************************* fi…

【FreeRTOS(一)】FreeRTOS新手入门——初识FreeRTOS

初识FreeRTOS一、实时操作系统概述1、概念2、RTOS的必要性3、RTOS与裸机的区别4、FreeRTOS的特点二、FreeRTOS的架构三、FreeRTOS的代码架构一、实时操作系统概述 1、概念 RTOS&#xff1a;根据各个任务的要求&#xff0c;进行资源&#xff08;包括存储器、外设等&#xff09…

剑指offer-二维数组中的查找

文章目录题目描述题解一 无脑暴力循环题解二 初始二分法&#x1f315;博客x主页&#xff1a;己不由心王道长&#x1f315;! &#x1f30e;文章说明&#xff1a;剑指offer-二维数组中的查找&#x1f30e; ✅系列专栏&#xff1a;剑指offer &#x1f334;本篇内容&#xff1a;对剑…