当前位置: 首页 > article >正文

【数据结构】二叉树的三种遍历(非递归讲解)

目录

1、前言

2、二叉树的非递归遍历

2.1、先序遍历

2.2、中序遍历

2.3、后序遍历


1、前言

学习二叉树的三种非递归遍历前,首先来了解一下递归序

递归序就是按照先序遍历的顺序,遇到的所有结点按顺序排列,重复的结点也必须记录。

我们可以发现递归序中每个结点都会遇到三次。

这是因为当进入某一结点时,对该结点进行第一次操作,然后调用其左孩子结点,等左孩子结点结束调用时会返回自己,此时就可以对自己进行第二次操作,然后再调用其右孩子结点,等左孩子结点结束调用时又会返回自己,此时就可以对自己进行第三次操作,因为不管怎样,调用完孩子结点后终究会返回到父结点。

直接给出结论:

递归序中第一次遇到该节点时打印结点,第二次第三次均不做任何操作,这就是先序遍历

递归序中第二次遇到该节点时打印结点,第一次第三次均不做任何操作,这就是中序遍历

递归序中第三次遇到该节点时打印结点,第一次第二次均不做任何操作,这就是后序遍历

关于递归序详细的讲解,可以看我之前写的一篇博客,里面有详细讲解,这里就不过多赘述:

【算法与数据结构】二叉树的三种遍历代码实现(上)—— 用递归序知识点讲解-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/133609612?spm=1001.2014.3001.5501

2、二叉树的非递归遍历

任何递归函数都可以改成非递归函数,因为递归函数不是什么玄学,只是递归时系统帮忙解决了压栈问题。那么不用递归方式的话只要自己手动进行压栈依然可以完成递归能够实现的功能。

有了上面递归序的知识点作为铺垫,就可以很好的理解非递归的实现了。

2.1、先序遍历

递归序中第一次遇到该节点时打印结点,第二次第三次均不做任何操作,这就是先序遍历

首先使用cur依次将二叉树所有左边界节点入栈,并且打印节点。当此时cur走到叶子节点后,将栈顶元素出栈,并让cur指向出栈元素的右孩子,继续进行左边界节点入栈操作。

    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new LinkedList<>();
        if(root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while(cur != null || !stack.isEmpty()) {
            if(cur != null) {
                stack.push(cur);
                System.out.print(cur.val + " ");  //第一次遇到时进行打印
                cur = cur.left;
            } else {
                cur =  stack.pop();   //第二次遇到
                cur = cur.right;
            }
        }
        return list;
    }

2.2、中序遍历

递归序中第二次遇到该节点时打印结点,第一次第三次均不做任何操作,这就是中序遍历。 

首先使用cur依次将二叉树所有左边界节点入栈。当此时cur走到叶子节点后,将栈顶元素出栈后并打印,此时第二次遇到该元素。然后让cur指向出栈元素的右孩子,继续进行左边界节点入栈操作。

    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new LinkedList<>();
        if(root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while(cur != null || !stack.isEmpty()) {
            if(cur != null) {
                stack.push(cur);   //第一次遇到
                cur = cur.left;
            } else {
                cur =  stack.pop();
                System.out.print(cur.val + " ");   //第二次遇到时进行打印
                cur = cur.right;
            }
        }
        return list;
    }

2.3、后序遍历

递归序中第三次遇到该节点时打印结点,第一次第二次均不做任何操作,这就是后序遍历

首先使用cur依次将二叉树所有左边界节点入栈。当此时cur走到叶子节点后,使用peek()查找出栈顶元素top(并非出栈)后并打印,然后判断top节点是否存在右孩子,当存在时则让cur指向top节点的右孩子,继续进行左边界节点入栈操作。当top不存在右孩子时则将栈顶元素出栈并打印栈顶元素,此时第三次遇到该元素。

    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new LinkedList<>();
        if(root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        TreeNode prev = null;
        while(cur != null || !stack.isEmpty()) {
            if(cur != null) {
                stack.push(cur);   //第一次遇到
                cur = cur.left;
            } else {
                TreeNode top = stack.peek();   //第二次遇到
                if(top.right != null && prev != top.right) {   //当该节点右子树不为空,并且之前没有去过右子树时
                    cur = top.right;						
                } else {     //该节点右子树为空或者是已经去过一次右子树了
                    top = stack.pop();
                    System.out.print(cur.val + " ");   //第三次遇到时进行打印
                    prev = top;
                }
            }
        }
        return list;
    }

博主推荐: 

【LeetCode力扣】单调栈解决Next Greater Number(下一个更大值)问题-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/136030138?spm=1001.2014.3001.5501 【数据结构】二叉搜索树的模拟实现-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/135910604?spm=1001.2014.3001.5501

 【LeetCode力扣】面试题 17.14. 最小K个数(top-k问题)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/135737266?spm=1001.2014.3001.5501

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!


http://www.kler.cn/a/231599.html

相关文章:

  • Java面试题2025-设计模式
  • shell脚本批量修改文件名之方法(The Method of Batch Modifying File Names in Shell Scripts)
  • 中间件安全
  • 开发环境搭建-4:WSL 配置 docker 运行环境
  • 编译dpdk19.08.2中example时一系列报错解决
  • 护眼好帮手:Windows显示器调节工具
  • 通过docker-compose部署NGINX服务,并使该服务开机自启
  • Fink CDC数据同步(四)Mysql数据同步到Kafka
  • 数据同步工具对比——SeaTunnel 、DataX、Sqoop、Flume、Flink CDC
  • 电力负荷预测 | 电力系统负荷预测模型(Python线性回归、随机森林、支持向量机、BP神经网络、GRU、LSTM)
  • golang 引入swagger(iris、gin)
  • Tkinter教程21:Listbox列表框+OptionMenu选项菜单+Combobox下拉列表框控件的使用+绑定事件
  • libevent源码解析--event,event_callback,event_base
  • 前端bug手册
  • 【npm】修改npm全局安装包的位置路径
  • 极智芯 | 解读国产CPU系列汇总
  • 【c++】STL详解(一):string类的使用
  • 子类将基类的虚函数替换为其自己的虚函数,共用的一个虚函数表,怎么不影响基类
  • 【python】绘制春节烟花
  • 微信小程序(三十九)表单信息收集
  • Java项目使用jasypt加密和解密配置文件中关键信息
  • Pycharm中以chrome打开HTML文件报错: Windows找不到文件‘Chrome‘
  • 使用SM4国密加密算法对Spring Boot项目数据库连接信息以及yaml文件配置属性进行加密配置(读取时自动解密)
  • navigator.mediaDevices.getUserMedia获取本地音频/麦克权限并提示用户
  • 本地部署TeamCity打包发布GitLab管理的.NET Framework 4.5.2的web项目
  • 【Kubernetes】kubectl top pod 异常?