【C++二叉树】二叉树的前序遍历、中序遍历、后序遍历递归与非递归实现

news/2024/9/22 14:32:26 标签: c++, 开发语言, 算法

1.二叉树的前序遍历

144. 二叉树的前序遍历 - 力扣(LeetCode)
 

前序遍历方式:根-左子树-右子树。

递归实现:

要传一个子函数来实先递归,原因是原函数返回值为vector,在原函数迭代,返回值就难处理了。

非递归(迭代)实现:

递归实现非常简单,非递归呢?

要用迭代实现,也就是循环:

还是按照根-左子树-右子树的遍历方式遍历。

遍历:先访问1、3、4再访问4的右子树再退回去访问3的右子树和1的右子树。

这时,我们可以把树分为左路节点和左路节点的右子树。

也就是先访问左路节点再访问左路节点的右子树,右子树也同样分为左路节点和左路节点的右子树。

这时,就要使用栈来解决:

  1. 把左路节点入栈,入栈的同时访问节点(遍历根),当左路节点为空时停止入栈,同时也证明左子树已经访问结束。
  2. 这时再访问左路节点的右子树。取栈顶数据(栈顶数据就是左路节点)的右子树,再把栈顶数据弹出。
  3. 右子树同样分为左路节点和左路节点的右子树,同样按照此方法迭代循环。
  4. 直到最后一个节点访问结束,此时,节点为空,栈为空。

自己根据代码,画一下图模拟迭代过程就容易理解了。

2.二叉树的中序遍历

94. 二叉树的中序遍历 - 力扣(LeetCode)

中序遍历方式:左子树-根-右子树。

递归实现:

非递归(迭代)实现:

中序遍历的非递归和前序遍历的非递归思路类似。

  1. 都是按照把树分为左路节点和左路节点的右子树的思路来实现的,只不过访问节点(根)的时机不同。
  2. 前序遍历是先访问根再访问左子树右子树,所以在左路节点入栈的时候,就访问节点(根),而中序遍历是先访问左子树再访问根再访问右子树
  3. 所以中序遍历是在左路节点入栈完以后,再访问节点(根)。

3.二叉树的后序遍历

145. 二叉树的后序遍历 - 力扣(LeetCode)

后序遍历方式:左子树-右子树-根

递归实现:

非递归迭代实现:

后序遍历方式:左子树-右子树-根

后序遍历的非递归与前序和中序的非递归整体思路类似。

唯一不同的就是访问节点的时机不同。

什么时候访问节点(根)呢?

  1. 从栈中取出左路节点时,节点的左子树已经访问完了(理解理解)。
  2. 当左路节点的右子树访问完才可以访问根。
  3. 如果左路节点的右子树为空,则代表右子树访问完,可以访问节点(根)了。
  4. 如果右子树不为空,则要先访问左路节点的右子树。

非递归迭代实现:

但是此时会发现超出了内存限制,说明代码有问题,内存限制问题一般就是死循环了。

按照上面的代码,会发现,节点3和节点5之间会一直死循环,

  1. 3的右子树不为空,把5入栈,5的右子树为空,把栈中5弹出来,下次循环又取了栈顶数据3,3的右子树不为空,把5入栈......
  2. 第二次访问节点3的时候,就应该直接访问节点(根)了,但他的右子树不为空,又访问了右子树,他不知道右子树已经访问过了,就会不断的进入3的右子树访问就死循环了。

所以,关键问题就说我们要想一个办法区分他的右子树到底访问过了没有,如果访问过了,则可以访问该左路节点(根)了,如果没有访问,则先访问他的右子树。

此时,可以使用双指针来解决,我们定义一个指针lastNode表示当前节点的上一个节点。

访问节点3的时候,lastNode为右子树的根(节点5),代表右子树已经访问完了,则就可以访问该节点了。

非递归(迭代)实现:



4.总结:

  • 前序遍历、中序遍历、后序遍历的递归实现很简单,但是非递归迭代实现就有稍微有点难理解了。
  • 用了同一种思路,把树分为左路节点和左路节点的右子树,针对这三种遍历方式都适用。
  • 从根本上就是用循环模拟递归的过程。
  • 后序遍历相对前序和中序又稍微复杂,要考虑好访问节点的条件,避免死循环。
  • 多画图模拟迭代的过程更容易理解。


http://www.niftyadmin.cn/n/5670419.html

相关文章

试图讲清楚spring的依赖注入

首先声明,依赖注入和反转容器是密不可分的,二者相互依存,依赖注入是实现反转控制的一种方式,允许对象在创建时将其依赖项提供给它,而不是在内部创建这些依赖项。这样可以增强代码的可测试性和可维护性。 spring依赖注入…

017_FEA_CSG_in_Matlab新的统一有限元分析工作流之2D几何

Matlab新的统一有限元分析工作流 从2023a开始,Matlab提供了一个统一有限元分析工作流(UFEAW,unified finite element analysis workflow)。 这个新的工作留提供一个统一的接口来求解三类问题,并且可以用同一套数据随…

使用vite+react+ts+Ant Design开发后台管理项目(一)

前言 本文将引导开发者从零基础开始,运用、react、react-router、react-redux、Ant Design、less、tailwindcss、axios等前沿技术栈,构建一个高效、响应式的后台管理系统。通过详细的步骤和实践指导,文章旨在为开发者揭示如何利用这些技术工…

无线麦克风哪个好,麦克风哪个品牌音质最好,领夹麦克风推荐

​无线领夹麦克风作为直播、视频录制等场景必备的设备之一,用起来很方便,功能多样且易于操作,在音频设备领域占据着重要地位。但当前市场乱象较为严重,有许多商家纷纷打起价格战,忽视了产品质量,造成耐用性…

C++ Primer:模板与泛型编程

1. 模板函数 在C中,模板与泛型编程是一种强大的编程范式,它允许程序员编写与类型无关的代码。这种类型无关的代码在编译时会被实例化,以支持特定的数据类型。下面是根据您提出的点,对模板函数及其相关概念的一个整理。 模板函数…

动手学深度学习(pytorch土堆)-05-1神经网络

Neural network 以下是 torch.nn 库中各个组件的详细分类: 1. 容器 (Containers) torch.nn.Sequential: 顺序容器,用于将层按顺序堆叠在一起。torch.nn.ModuleList: 模块列表,用于存储多个子模块。torch.nn.ModuleDict: 模块字典&#xff…

机械设备产品资料方案介绍小程序系统开发制作

设备产品资料介绍小程序系统,是一家工业机械设备生产厂家为了更好的服务客户而定制开发的一套小程序系统,让用户通过小程序就可以了解公司产品介绍的详细参数、售后服务和产品操作手持等。 该小程序系统里面主要开发的功能模块有: 1、产品目…

MATLAB基础应用精讲-【数模应用】RR值

目录 前言 RR值在不同领域的应用 不同领域中RR值的计算方法和意义 几个高频面试题目 RR,RRR,ARR,NNT指标详解 RR、OR、HR:区别、计算与适用场景 计算方法 (一)相对危险度(Relative risk) (二)优势比(Odds ratio,OR) (三)风险比(hazard raito) 算法原…