【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.总结:

  • 前序遍历、中序遍历、后序遍历的递归实现很简单,但是非递归迭代实现就有稍微有点难理解了。
  • 用了同一种思路,把树分为左路节点和左路节点的右子树,针对这三种遍历方式都适用。
  • 从根本上就是用循环模拟递归的过程。
  • 后序遍历相对前序和中序又稍微复杂,要考虑好访问节点的条件,避免死循环。
  • 多画图模拟迭代的过程更容易理解。
相关推荐
懒大王爱吃狼33 分钟前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
劲夫学编程34 分钟前
leetcode:杨辉三角
算法·leetcode·职场和发展
毕竟秋山澪36 分钟前
孤岛的总面积(Dfs C#
算法·深度优先
秃头佛爷2 小时前
Python学习大纲总结及注意事项
开发语言·python·学习
待磨的钝刨2 小时前
【格式化查看JSON文件】coco的json文件内容都在一行如何按照json格式查看
开发语言·javascript·json
浮生如梦_3 小时前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
XiaoLeisj4 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
励志成为嵌入式工程师5 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉5 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer5 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法