二叉树的前序-中序-后序遍历

news2025/1/11 1:35:50

在牛客网刷到了二叉树的遍历,二叉树的遍历分为前序遍历,前序遍历也有先序遍历之称,还有中序遍历,以及后序遍历,这么多种遍历,遍历的方式不一样而已,前序遍历是先遍历根然后左节点然后是右节点,就是根左右,中序遍历的话是左根右,后序遍历是左右根,

1种:一般遍历采取递归方式,比如根左右,在调用左节点一直递归直到找到左边结束,到某个节点分叉口时再继续遍历邻节点也是同样方式一直递归,直到所有节点递归完,

2种:除了递归以外也可以通过栈(先进后出,后进的先出)方式遍历树,先把树根节点存储到栈里,然后开始取出树根存储到集合里,继续往栈里存放先放右节点,再放左节点,这样继续循环取就先取左边的数据了。

准备工作,我们先来定义二叉树的节点TreeNode

public class TwoTreeBeforeIterable {

   public static class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;

        public TreeNode(int val) {
            this.val = val;
        }
    }
}

1.前序遍历

咱们先实现个用栈思想来进行前序遍历操作

    // 利用栈思想,先进后出
    public static int[] preorderTraversal1(TreeNode root) {
        LinkedList<Integer> list = new LinkedList<>();
        if (root == null) {
            return new int[0];
        }
        // 先把树节点存放在栈种
        ArrayDeque<TreeNode> que = new ArrayDeque<>();
        que.push(root);
        while (!que.isEmpty()) {
            // 取出树节点
            TreeNode node = que.pop();
            // 存储节点
            list.add(node.val);

            //根左右,由于栈是先进后出,所以要让左节点后入栈,这样才能先弹出来
            if (node.right != null) {
                // 先往栈里存放右节点
                que.push(node.right);
            }
            if (node.left != null) {
                // 再往栈里存放左节点
                que.push(node.left);
            }

        }
        return list.stream().mapToInt(Integer::intValue).toArray();
    }

                                        5

                              4                6

                         1       2 

测试:

public static void main(String[] args) {

        // 生成树结构开始
        TreeNode treeNode = new TreeNode(5);
        TreeNode treeLeftNode = new TreeNode(4);
        TreeNode treeRightNode = new TreeNode(6);


        TreeNode treeLeftLeftNode = new TreeNode(1);
        TreeNode treeRightRightNode = new TreeNode(2);

        treeNode.left = treeLeftNode;
        treeNode.right = treeRightNode;

        treeLeftNode.left = treeLeftLeftNode;
        treeLeftNode.right = treeRightRightNode;

        treeRightNode.right = null;
        treeRightNode.left = null;
        // 生成树结构结束

        int[] s = TwoTreeBeforeIterable.preorderTraversal1(treeNode);
        System.out.println(Arrays.toString(s));
}

结果:

[5, 4, 1, 2, 6]

递归实现下先序遍历,递归这种方式也叫深度优先遍历,

深度优先遍历先找到当前节点,然后沿着某一节点一直走到底,再通过节点返回走下一节点邻节点,

根左右,所以再存list时先存储root.val,然后再递归左边,左边深度遍历完毕,再递归节点右部,直到全部遍历完毕

public static int[] preorderTraversal2(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        dfs(list, root);
        return list.stream().mapToInt(Integer::intValue).toArray();
 }
public static void dfs(List<Integer> list, TreeNode root) {
        if (root != null) {
            list.add(root.val);
            dfs(list, root.left);
            dfs(list, root.right);
        }
    }

 用刚才的示例测试递归方式的,结果是一样的

中序遍历

其实按照递归方式,我们很容易的就能实现二叉树的中序遍历,在递归时,先递归左部,再存储到list值,再递归右部即可。


    // 二叉树中序遍历--------------------------------------------------------开始
    // 左根右
    public static int[] preorderTraversal3Mid(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        dfsMid(list, root);
        return list.stream().mapToInt(Integer::intValue).toArray();
    }

    public static void dfsMid(List<Integer> list, TreeNode root) {
        if (root != null) {
            dfsMid(list, root.left);
            list.add(root.val);
            dfsMid(list, root.right);
        }
    }


    // 二叉树中序遍历--------------------------------------------------------结束

                                       5

                              4                6

                         1       2 

结果:[1, 4, 2, 5, 6]

后序遍历

后序遍历是左右根,前序遍历和中序遍历,你都知道了,那后序遍历就不用多说了

 // 二叉树后序遍历--------------------------------------------------------开始
    // 左右根遍历
    public static int[] preorderTraversal3Back(TreeNode root) {
        ArrayList<Integer> que = new ArrayList<>();
        dfsBack(que, root);
        return que.stream().mapToInt(Integer::intValue).toArray();
    }

    public static void dfsBack(ArrayList<Integer> que, TreeNode root) {
        if (root != null) {
            dfsBack(que, root.left);
            dfsBack(que, root.right);
            que.add(root.val);
        }
    }

    /*
    *
    *
    *                          1
    *                   2                3
    *            4          5      6         7
    * 后序递归遍历分析:
    * 代码逻辑是先找左边递归
    * 1.这样进来就先找到1的left,再次进入递归得到left2,再次进入递归得到left4,再此进入左节点为空,得到右节点为空
    * 此时把4存储起来que.add(root.val);
    * 2.4的上一个节点2递归到右边找到5,找到5的节点的左右节点,发现没有把5存储起来que.add(root.val);
    * 3.5的上一个节点2(左右都递归完毕)递归完毕,把2存储起来que.add(root.val);
    * 4.root就变为1节点,root此时的左边节点全部找到,开始处理右部节点3,找3的左部节点为6,再找6的左节点发现没有,递归结束,再找6的右节点也没有
    *   开始存储6 que.add(root.val);
    * 5.此时root节点变为3,找3的右节点为7,找7的左节点为空,找7的右节点为空,此时存储7que.add(root.val);
    * 6.此时3的左右节点全部遍历完毕,直接存储3 que.add(root.val);
    * 7.此时1的左右节点全部遍历完毕,直接存储1 que.add(root.val);
    * 最终按照左右根方式输出为:[4, 5, 2, 6, 7, 3, 1]
    *     **/

    // 二叉树后序遍历--------------------------------------------------------结束

 测试一下

                                           1

                            2                          3

                 4                   5          6              7

        TreeNode treeNode = new TreeNode(1);
        TreeNode treeLeftNode = new TreeNode(2);
        TreeNode treeRightNode = new TreeNode(3);


        treeNode.left = treeLeftNode;
        treeNode.right = treeRightNode;

        TreeNode treeLeftLeftNode = new TreeNode(4);
        TreeNode treeLeftRightNode = new TreeNode(5);
        treeLeftNode.left = treeLeftLeftNode;
        treeLeftNode.right = treeLeftRightNode;

        TreeNode treerightLeftNode = new TreeNode(6);
        TreeNode treeRightRightNode = new TreeNode(7);
        treeRightNode.left = treerightLeftNode;
        treeRightNode.right = treeRightRightNode;

        int[] s = TwoTreeBeforeIterable.preorderTraversal3Back(treeNode);
        System.out.println(Arrays.toString(s));

结果:[4, 5, 2, 6, 7, 3, 1]

时间复杂度空间复杂度都为O(n)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/94920.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

两年前端的2022:24岁、辗转三省、进入阿里

前言 前排声明&#xff1a;文中主人公不是博主&#xff0c;另外本文只是一些朋友在工作、生活上的经历和琐碎&#xff0c;想看技术干货的掘友请止步&#xff0c;不要在本文上浪费你的学习时间~~~ 2022年&#xff0c;也实实在在满24岁了&#xff0c;毕业进入社会两年多&#xff…

我与外企上司的四个职场故事

标题&#xff1a;我与外企上司的四个职场故事 我在目前这家任职的外企从事软件开发工作&#xff0c;已经整整十五年了。本系列文章通过介绍我与自己上司的四个职场小故事&#xff0c;想和大家分享在外企里&#xff0c;一个程序员除了埋头提升自己技术之外&#xff0c;还有哪些…

数据自动录入并生成报表神器怎么玩?

做报表、分析数据、做汇报是许多打工人的日常&#xff0c;每天都要耗费不少的时间用Excel来整理、清洗数据和生成好看的报表。如果这些数据都是手动整理、复制粘贴的话&#xff0c;不仅费时费力&#xff0c;而且很容易出错。 在越来越多企业采用SaaS产品和不同数据应用的今天&…

没有任何销售经验怎么进行销售团队管理?

没有任何销售经验想要进行销售团队管理&#xff0c;并不是一件容易的事情。每一行都有值得研究和学习的地方&#xff0c;需要学习补充的知识点还是比较多的。 参考《销售管理管理成长手册》&#xff0c;本文为您讲解以下管理知识&#xff0c;包括&#xff1a;1、明白销售经理是…

春招升级打怪拿offer,10w+字总结的Java面试题(附答案)够你刷

春招升级打怪拿offer&#xff0c;献上熬夜整理最新“10w字总结的Java面试题&#xff08;附答案&#xff09;”够你刷&#xff01; 其包含的内容模块有&#xff1a;基础、JVM、多线程与高并发、Spring、MyBatis、SpringBoot、MYSQL、SpringCloud、Dubbo、Nginx、MQ、数据结构与算…

libevent实战学习

目录 编译安装libevent libevent 事件对象 事件操作 事件循环 事件处理 libevent 客户端demo libevent 服务端demo libevent 服务端升级demo libevent完整demo 总结 C/CLinux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂 编译安装libevent git上下载h…

十分钟彻底搞懂python异常

异常 目标 异常的概念捕获异常异常的传递抛出异常 01. 异常的概念 程序在运行时&#xff0c;如果 Python 解释器 遇到 到一个错误&#xff0c;会停止程序的执行&#xff0c;并且提示一些错误信息&#xff0c;这就是 异常程序停止执行并且提示错误信息 这个动作&#xff0c;…

真无线耳机哪个品牌音质最好?半入耳式真无线蓝牙耳机推荐

对于社恐的人来说&#xff0c;出门在外都会选择佩戴上耳机&#xff0c;那么这种情况下&#xff0c;一款高品质的耳机真的是必不可少的&#xff0c;选择了一款性能优秀的耳机&#xff0c;不光能够让自己听音乐的过程中有更好的体验感&#xff0c;同时还能舒缓身心&#xff0c;让…

编程常见的问题(三) 线程池

编程常见的问题(三) 线程池 今天&#xff0c;我来讲讲使用线程池需要注意的一些问题。 在程序中&#xff0c;我们会用各种池化技术来缓存创建昂贵的对象&#xff0c;比如线程池、连接池、内存池。一般是预先创建一些对象放入池中&#xff0c;使用的时候直接取出使用&#xff…

[附源码]Node.js计算机毕业设计高校运动会管理系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

阿里三面,mmap 没答好!

1、mmap基础概念 mmap 是一种内存映射文件的方法&#xff0c;即将一个文件或者其他对象映射到进程的地址空间&#xff0c;实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一映射关系。 实现这样的映射关系后&#xff0c;进程就可以采用指针的方式读写操作这一段内存&a…

给你30s,如何跟面试官讲清楚跳表

查找 假设有如下这样一个有序链表&#xff1a; 想要查找 24、43、59&#xff0c;按照顺序遍历&#xff0c;分别需要比较的次数为 2、4、6 目前查找的时间复杂度是 O(N)&#xff0c;如何提高查找效率&#xff1f; 很容易想到二分查找&#xff0c;将查找的时间复杂度降到 O(Lo…

MipNeRF:多尺度、抗混叠NeRF

Mip-NeRF: A Multiscale Representation for Anti-Aliasing Neural Radiance Fields ​ ICCV 2021 文章目录Mip-NeRF: A Multiscale Representation for Anti-Aliasing Neural Radiance Fields原始NeRF的问题重点componentsCone TracingIPE-integrated positional encodingPE与…

微服务框架 SpringCloud微服务架构 多级缓存 47 Lua 语法入门 47.2 变量和循环

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 多级缓存 文章目录微服务框架多级缓存47 Lua 语法入门47.2 变量和循环47.2.1 数据类型47.2.2 变量47.2.3 循环47 Lua 语法入门 47.2 变量和…

人脸识别Face Recognition综述

综述&#xff1a;https://arxiv.org/pdf/2009.13290.pdf 人脸识别整个系统一般由三个关键要素构成&#xff1a;人脸检测&#xff08;face detection&#xff09;、人脸预处理&#xff08;face preprocess&#xff09;&#xff0c;人脸表征&#xff08;face representation&…

EtherCAT设备协议详解一、EtherCAT概述

EtherCAT简介&#xff1a; • 用于控制自动化技术的以太网&#xff08;EtherCAT&#xff09; 是一种基于以太网的现场总线系统 – 由倍福自动化™于2003年发明 – Beckhoff 创建了 EtherCAT 技术集团&#xff08;ETG&#xff09;于2004年推广议定书 –…

DBCO 点击化学:DBCO-PEG-COOH,DBCO-PEG-acid,羧基聚乙二醇环辛炔

一、产品描述&#xff1a; 西安凯新生物科技有限公司供应的&#xff1a;​DBCO-PEG-COOH&#xff0c;末端羧酸在活化剂&#xff08;如EDC或HATU&#xff09;存在下可与伯胺基反应&#xff0c;形成稳定的酰胺键。DBCO 点击化学可以在水性缓冲液中运行&#xff0c;也可以在有机溶…

来啦|深度讲解风控模型中的参数调优

大数据时代的风控体系必有模型部分的参与&#xff0c;用策略贯穿整个风控体系&#xff0c;以数据为驱动&#xff0c;模型一定是标配内容。于是在模型的建设上&#xff0c;如何精细化地输出一套有效的模型&#xff0c;就是在精细化管理上非常重要的一个差异点。不管传统的逻辑回…

MATLAB处理语音信号基本函数、模块

目录 一、sound函数 二、symerr函数用来计算错误码元数目和误码率 三、From Workspace 模块 四、To Workspace模块 一、sound函数 sound函数可以用来播放音频数据&#xff0c;将矩阵变为立体声播放。 二、symerr函数用来计算错误码元数目和误码率 三、From Workspace 模…

【High 翻天】Higer-order Networks with Battiston Federico (2)

目录测量矩阵表示中心化测度度&#xff08;degree&#xff09;路径&#xff08;path&#xff09;特征向量中心三元闭包和聚类系数单纯同调高阶Lapalacian算子超图拉普拉斯组合拉普拉斯接上回说到了高阶的表示方法&#xff0c;接下来开始高阶系统的测量方法。 测量 具体来说就…