非递归方式实现二叉树的前、中、后序遍历

简介: 非递归方式实现二叉树的前、中、后序遍历

二叉树的前序遍历


虽然我们说的是不用递归的方式实现,但是我们的思路还是模拟递归的实现,那么我们如何不用递归来模拟实现递归呢?我们要想模拟递归,我们需要知道实现递归的底层逻辑是什么?递归实际上是通过栈这个数据结构来实现的,我们都知道递归的顺序是先完成后递归的,这也就跟栈先进后出的原理是类似的,所以我们想模拟递归,也需要借用栈这个数据结构。


在知道了原理之后,我们接下来就需要知道怎么样来实现了,因为这里是前序遍历,先遍历根节点,然后是左子树,最后是右子树,所以我们先遍历左子树,并且在遍历的同时我们将遍历的节点存储在栈中并打印,方便我们找到节点的右子树。当我们的root遍历到为null时,就说明左树遍历完了,我们就将栈顶的节点弹出,将root等于弹出节点的右子树,直到root等于null并且栈为空时完成遍历。

1.png

2.png

3.png

节点6的右树也为null,所以我们弹出栈顶的元素,cur = top.right,继续上面操作。

4.png

5.png

6.png

7.png

public void preOrderNor(TreeNode root) {
        if(root == null) {
            return;
        }
        TreeNode cur = root;
        Deque<TreeNode> stack = new ArrayDeque<>();
        while(cur != null || !stack.isEmpty()) {
            while(cur != null) {
                stack.push(cur);
                System.out.println(cur.val);
                cur = cur.left;
            }
            TreeNode top = stack.pop();
            cur = top.right;
        }
    }

二叉树的中序遍历

中序遍历的思路跟前序遍历的思路是一样的,只是打印的顺序不同,我们在从栈中弹出节点的同时打印。

public void inOrderNor(TreeNode root) {
        if(root == null) {
            return;
        }
        Deque<TreeNode> stack = new ArrayDeque<>();
        TreeNode cur = root;
        while(cur != null || !stack.isEmpty()) {
            while(cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode top = stack.pop();
            System.out.println(top.val);
            cur = top.right;
        }
    }

二叉树的后序遍历

后序遍历的思路跟前序和中序的思路是不同的,我们需要判断什么时候该打印,因为是后序遍历,所以我们需要在遍历完右树或者右树为null的时候在遍历根节点。

8.png

9.png

10.png

11.png

12.png

public void postOrderNor(TreeNode root) {
        if(root == null) {
            return;
        }
        TreeNode cur = root;
        TreeNode prev = null;
        Deque<TreeNode> stack = new ArrayDeque<>();
        while(cur != null || !stack.isEmpty()) {
            while(cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode top = stack.peek();
            if(top.right == null || top.right == prev) {
                System.out.println(top.val);
                stack.pop();
                prev = top;
            }else {
                cur = top.right;
            }
        }
    }


相关文章
|
Java 编译器 API
protobuf万字语法详解
当用protocol buffer编译器来运行.proto文件时,编译器将生成所选择语言的代码,这些代码可以操作在.proto文件中定义的消息类型,包括获取、设置字段值,将消息序列化到一个输出流中,以及从一个输入流中解析消息。
359 0
protobuf万字语法详解
|
JSON 测试技术 数据处理
iOS-底层原理 35:组件化(一)方案
iOS-底层原理 35:组件化(一)方案
1678 0
iOS-底层原理 35:组件化(一)方案
|
运维 资源调度 Kubernetes
Kubernetes Scheduler Framework 扩展: 1. Coscheduling
# 前言 ## 为什么Kubernetes需要Coscheduling功能? Kubernetes目前已经广泛的应用于在线服务编排,为了提升集群的的利用率和运行效率,我们希望将Kubernetes作为一个统一的管理平台来管理在线服务和离线作业。但是默认的调度器是以Pod为调度单元进行依次调度,不会考虑Pod之间的相互关系。但是很多数据计算类的作业具有All-or-Nothing特点,要求所有的
3540 0
|
存储 缓存 关系型数据库
图解MySQL【日志】——Redo Log
Redo Log(重做日志)是数据库中用于记录数据页修改的物理日志,确保事务的持久性和一致性。其主要作用包括崩溃恢复、提高性能和保证事务一致性。Redo Log 通过先写日志的方式,在内存中缓存修改操作,并在适当时候刷入磁盘,减少随机写入带来的性能损耗。WAL(Write-Ahead Logging)技术的核心思想是先将修改操作记录到日志文件中,再择机写入磁盘,从而实现高效且安全的数据持久化。Redo Log 的持久化过程涉及 Redo Log Buffer 和不同刷盘时机的控制参数(如 `innodb_flush_log_at_trx_commit`),以平衡性能与数据安全性。
816 5
图解MySQL【日志】——Redo Log
|
API 网络架构
一文带你了解 Flutter 路由
一文带你了解 Flutter 路由
497 5
|
Linux 调度
Linux源码阅读笔记05-进程优先级与调度策略-实战分析
Linux源码阅读笔记05-进程优先级与调度策略-实战分析
|
算法 Linux 调度
Linux源码阅读笔记03-调度器及CFS调度器
Linux源码阅读笔记03-调度器及CFS调度器
|
网络协议 搜索推荐
网络中的单播、多播和广播
【8月更文挑战第24天】
919 0
|
SQL 物联网 大数据
TDengine的主要特性有哪些?
【5月更文挑战第13天】TDengine的主要特性有哪些?
491 10
|
算法
简单的KMP的next、nextval数组求解办法(存档自己用来复习)
简单的KMP的next、nextval数组求解办法(存档自己用来复习)
1543 2

热门文章

最新文章