庖丁解牛-二叉树的遍历

庖丁解牛-二叉树的遍历

在这里插入图片描述

〇、前言

01 文章内容

  • 一般提到二叉树的遍历,我们是在说
    • 前序遍历、中序遍历、后序遍历和层序遍历
  • 或者说三序遍历+层序遍历,毕竟三序和层序的遍历逻辑相差比较大
  • 下面讨论三序遍历的递归方法、非递归方法和非递归迭代的统一方法
  • 然后再讨论一下层序的一般迭代方法(通过队列)

02 力扣网址

  • 144. 二叉树的前序遍历 - 力扣(LeetCode)
  • 94. 二叉树的中序遍历 - 力扣(LeetCode)
  • 145. 二叉树的后序遍历 - 力扣(LeetCode)

一、前序遍历

01 递归实现

  • 递归的基本逻辑是比较简单的,但是注意根据题目的需求不同,实现方式是存在差异的
  • 如果题目要求主函数返回一个结果列表,那么就要构造一个辅助函数来帮助实现
  • 如果题目只要求函数打印前序遍历的序列,那么一个函数就足够了
(1) 返回列表版本1

返回列表版本:辅助函数携带结果列表

public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    inorderTraversalHelper(root,result);
    return result;

}
void preorderTraversalHelper(TreeNode root,List<Integer> result){
    if(root == null) return;
    result.add(root.val);
    inorderTraversalHelper(root.left,result);
    inorderTraversalHelper(root.right,result);
    return;
}
(2) 返回列表版本2

返回列表版本:设置全局变量

List<Integer> result = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {
    inorderTraversalHelper(root,result);
    return result;
}
void preorderTraversalHelper(TreeNode root){
    if(root == null) return;
    result.add(root.val);
    inorderTraversalHelper(root.left,result);
    inorderTraversalHelper(root.right,result);
    return;
}
(3) 纯真打印版本
public List<Integer> preorderTraversal(TreeNode root) {
    inorderTraversalHelper(root,result);
    return result;
}
void preorderTraversal(TreeNode root){
    if(root == null) return;
    System.out.print(root.val);
    inorderTraversalHelper(root.left,result);
    inorderTraversalHelper(root.right,result);
    return;
}
(4) 面向对象版本
class Solution {
    class TraverBox{
        List<Integer> list;
        TraverBox(){
            list = new ArrayList<>();
        }
        void preorderTraversalHelper(TreeNode root) {
            list.add(root.val);
        }
        void preTraverHelper(TreeNode root) {
            if(root == null) return;
            list.add(root.val);
            preTraverHelper(root.left);
            preTraverHelper(root.right);
        }
        List<Integer> preTraver(TreeNode root) {
            preTraverHelper(root);
            return list;
        }
    }

    public List<Integer> preorderTraversal(TreeNode root) {
        TraverBox tox = new TraverBox();
        tox.preTraver(root);
        return tox.list;
    }
}

02 非递归实现

(1) 一般迭代法

(2) 统一迭代法
public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> result = new LinkedList<>();
    Stack<TreeNode> stack = new Stack<>();
    TreeNode subRoot = new TreeNode();

    if (root != null) stack.push(root); //将根结点入栈
    while(!stack.isEmpty()){
        subRoot = stack.pop(); //弹出获取栈顶结点
        if(subRoot != null){
            //===右===
            if(subRoot.right != null){
                // 添加右结点(空结点不入栈)
                stack.push(subRoot.right);
            }
            //===左===
            if(subRoot.left != null){
                // 添加左节点(空结点不入栈)
                stack.push(subRoot.left);
            }
            //===中===
            stack.push(subRoot); // 添加中结点
            stack.push(null); // 中结点访问过,但是还没有处理,加入空结点做为标记。
        }else{ // 只有遇到空结点的时候,才将下一个结点放进结果集
            result.add(stack.pop().val); //重新取出栈中元素,加入到结果集
        }
    }
    return result;
}

二、中序遍历

01 递归实现

(1) 返回列表版本1

返回列表版本:辅助函数携带结果列表

public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    inorderTraversalHelper(root,result);
    return result;

}
void preorderTraversalHelper(TreeNode root,List<Integer> result){
    if(root == null) return;
    inorderTraversalHelper(root.left,result);
    result.add(root.val);
    inorderTraversalHelper(root.right,result);
    return;
}
(2) 返回列表版本2

返回列表版本:设置全局变量

List<Integer> result = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {
    inorderTraversalHelper(root,result);
    return result;
}
void preorderTraversalHelper(TreeNode root){
    if(root == null) return;
    inorderTraversalHelper(root.left,result);
    result.add(root.val);
    inorderTraversalHelper(root.right,result);
    return;
}
(3) 纯真打印版本
void preorderTraversal(TreeNode root){
    if(root == null) return;
    inorderTraversalHelper(root.left,result);
    System.out.print(root.val);
    inorderTraversalHelper(root.right,result);
    return;
}

02 非递归实现

(1) 一般迭代法
void inOrderNonRecur(){
    Stack<TreeNode> stack = new Stack<>();
    TreeNode subRoot = root;
    if (subRoot != null) {
        while (!stack.isEmpty() || subRoot != null) {
            if (subRoot != null) {
                stack.push(subRoot);
                subRoot = subRoot.left;
            } else {
                subRoot = stack.pop();
                System.out.print("【"+subRoot.val+"】");
                subRoot = subRoot.right;
            }
        }
    }
}
(2) 统一迭代法

带注释版本

public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> result = new LinkedList<>();
    Stack<TreeNode> stack = new Stack<>();
    TreeNode subRoot = new TreeNode();

    if (root != null) stack.push(root);
    while (!stack.isEmpty()) {
        subRoot = stack.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
        if (subRoot != null) {
            //===右===
            if(subRoot.right != null){
                // 添加右节点(空节点不入栈)
                stack.push(subRoot.right);
            }
            //===中===
            stack.push(subRoot); // 添加中节点
            stack.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。
            //===左===
            if(subRoot.left != null){
                // 添加左节点(空节点不入栈)
                stack.push(subRoot.left);
            }
        } else { // 只有遇到空节点的时候,才将下一个节点放进结果集
            result.add(stack.pop().val); // 加入到结果集
        }
    }
    return result;
}

无注释版本

public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> result = new LinkedList<>();
    Stack<TreeNode> stack = new Stack<>();
    TreeNode subRoot = new TreeNode();

    if (root != null) stack.push(root);
    while (!stack.isEmpty()) {
        subRoot = stack.pop();
        if (subRoot != null) {
            if(subRoot.right != null) stack.push(subRoot.right);
            stack.push(subRoot);
            stack.push(null);
            if(subRoot.left != null) stack.push(subRoot.left);
        } else {
            result.add(stack.pop().val);
        }
    }
    return result;
}

三、后序遍历

01 递归实现

(1) 返回列表版本1

返回列表版本:辅助函数携带结果列表

public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    inorderTraversalHelper(root,result);
    return result;

}
void preorderTraversalHelper(TreeNode root,List<Integer> result){
    if(root == null) return;
    inorderTraversalHelper(root.left,result);
    inorderTraversalHelper(root.right,result);
    result.add(root.val);
    return;
}
(2) 返回列表版本2

返回列表版本:设置全局变量

List<Integer> result = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {
    inorderTraversalHelper(root,result);
    return result;
}
void preorderTraversalHelper(TreeNode root){
    if(root == null) return;
    inorderTraversalHelper(root.left,result);
    inorderTraversalHelper(root.right,result);
    result.add(root.val);
    return;
}
(3) 纯真打印版本
void preorderTraversal(TreeNode root){
    if(root == null) return;
    inorderTraversalHelper(root.left,result);
    inorderTraversalHelper(root.right,result);
    System.out.print(root.val);
    return;
}

02 非递归实现

(1) 一般迭代法
public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    if (root != null) {
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.push(root);
        TreeNode subRoot = null;
        while (!stack.isEmpty()) {
            subRoot = stack.peek();
            if (subRoot.left != null && root != subRoot.left && root != subRoot.right) {
                stack.push(subRoot.left);
            } else if (subRoot.right != null && root != subRoot.right) {
                stack.push(subRoot.right);
            } else {
                result.add(stack.pop().val);
                root = subRoot;
            }
        }
    }
    return result;
}
(2) 双栈迭代法
public List<Integer> postOrderNonRecurByTwoStack(){
    List<Integer> result = new ArrayList<>();
    TreeNode subRoot = root;
    if (subRoot != null) {
        Stack<TreeNode> s1 = new Stack<TreeNode>();
        Stack<TreeNode> s2 = new Stack<TreeNode>();
        s1.push(subRoot);
        while (!s1.isEmpty()) {
            subRoot = s1.pop();
            s2.push(subRoot);
            if (subRoot.left != null) {
                s1.push(subRoot.left);
            }
            if (subRoot.right != null) {
                s1.push(subRoot.right);
            }
        }
        while (!s2.isEmpty()) {
            result.add(s2.pop().val);
        }
    }
}
(3) 统一迭代法
public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> result = new LinkedList<>();
    Stack<TreeNode> stack = new Stack<>();
    TreeNode subRoot = new TreeNode();

    if (root != null) stack.push(root); //将根结点入栈
    while(!stack.isEmpty()){
        subRoot = stack.pop(); //弹出获取栈顶结点
        if(subRoot != null){
            //===中===
            stack.push(subRoot); // 添加中结点
            stack.push(null); // 中结点访问过,但是还没有处理,加入空结点做为标记。
            //===右===
            if(subRoot.right != null){
                // 添加右结点(空结点不入栈)
                stack.push(subRoot.right);
            }
            //===左===
            if(subRoot.left != null){
                // 添加左节点(空结点不入栈)
                stack.push(subRoot.left);
            }
        }else{ // 只有遇到空结点的时候,才将下一个结点放进结果集
            result.add(stack.pop().val); //重新取出栈中元素,加入到结果集
        }
    }
    return result;
}

四、层序遍历

01 不分层输出

class Solution {
    public int[] levelOrder(TreeNode root) {
        //if(root == null) return new int[]{};
        ArrayList<Integer> result = new ArrayList<Integer>();
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        TreeNode subRoot = new TreeNode();
        
        if(root != null) queue.offer(root);
        while(!queue.isEmpty()){
            subRoot = queue.poll();
            result.add(subRoot.val);
            if(subRoot.left != null) queue.add(subRoot.left);
            if(subRoot.right != null) queue.add(subRoot.right);
        }
        
        int[] dest = new int[result.size()];
        for(int i = 0 ; i < result.size() ; i++){
            dest[i] = result.get(i);
        }
        return dest;
    }
}

02 分层输出

public List<List<Integer>> levelOrder(TreeNode root) {
    List<List<Integer>> ret = new ArrayList<List<Integer>>();
    if (root == null) {
        return ret;
    }

    Queue<TreeNode> queue = new LinkedList<TreeNode>();
    queue.offer(root);
    while (!queue.isEmpty()) {
        List<Integer> level = new ArrayList<Integer>();
        int currentLevelSize = queue.size();
        for (int i = 1; i <= currentLevelSize; ++i) {
            TreeNode node = queue.poll();
            level.add(node.val);
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
        }
        ret.add(level);
    }

    return ret;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

调度服务看门狗配置

查看当前服务器相关的sqlserver服务 在任务栏右键&#xff0c;选择点击启动任务管理器 依次点击&#xff0c;打开服务 找到sqlserver 相关的服务&#xff0c; 确认这些服务是启动状态 将相关服务在看门狗中进行配置 选择调度服务&#xff0c;双击打开 根据上面找的服务进行勾…

MTR(My Traceroute)网络链路路由测试工具

一、MTR的介绍 MTR是一款网络诊断工具&#xff0c;它将ping和traceroute的功能结合到一个程序中。这个工具可以提供关于网络链路的详细信息,显示数据包在网络上的传输路径&#xff0c;并提供有关每个节点的详细信息&#xff0c;如丢包率、延迟等。与传统的traceroute工具相比&a…

Python爬虫-爬取B站番剧封面

本文是本人最近学习Python爬虫所做的小练习。如有侵权&#xff0c;请联系删除。 页面获取url 代码 import requests import os import re# 创建文件夹 path os.getcwd() /images if not os.path.exists(path):os.mkdir(path)# 当前页数 page 1 # 总页数 total_page 2# 自动…

淘宝天猫商品详情API接口(商品详情页面数据,销量接口)

淘宝商品详情API接口&#xff0c;淘宝商品销量接口&#xff0c;淘宝商品价格接口&#xff0c;淘宝商品列表接口&#xff0c;淘宝商品数据列表接口&#xff0c;淘宝关键词搜索列表接口&#xff0c;淘宝APP详情接口&#xff0c;淘宝APP商品详情接口&#xff0c;淘宝H5详情接口&am…

【FPGA】线性反馈移位寄存器(LFSR)的Verilog实现

什么是移位寄存器 移位寄存器&#xff1a;是指多个寄存器并排相连&#xff0c;前一个寄存器的输出作为下一个寄存器的输入&#xff0c;寄存器中存放的数据在每个时钟周期向左或向右移动一位。 下面的右移移位寄存器因为左侧没有有效输入&#xff0c;所以在第4个时钟周期&…

【C语言】linux内核netdev_start_xmit函数

一、中文注释 static inline netdev_tx_t netdev_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq, bool more) {// 获取网络设备操作集合const struct net_device_ops *ops dev->netdev_ops;int rc;// 调用实际发送数据包的函数&…

2024年环境安全科学、材料工程与制造国际学术会议(ESSMEM2024)

【EI检索】2024年环境安全科学、材料工程与制造国际学术会议&#xff08;ESSMEM2024) 会议简介 我们很高兴邀请您参加将在三亚举行的2024年环境安全科学、材料工程和制造国际学术会议&#xff08;ESSMEM 2024&#xff09;。 ESSMEM2024将汇集世界各国和地区的研究人员&…

前后端分离Vue+node.js在线学习考试系统gqw7o

与其它应用程序相比&#xff0c;在线学习平台的设计主要面向于学校&#xff0c;旨在为管理员和学生、教师、院系提供一个在线学习平台。学生、教师、院系可以通过系统及时查看公告信息等。 在线学习平台是在Windows操作系统下的应用平台。为防止出现兼容性及稳定性问题&#xf…

前端网页位置

网页可见区域高&#xff1a;document.body.clientHeight&#xff08;不包括边线的高&#xff09; 网页可见区域高&#xff1a;document.body.offsetHeight&#xff08;包括边线的高&#xff09; 网页正文全文高&#xff1a;document.body.scrollHeight 网页被卷去的高度&#x…

数字化转型与制造企业绿色创新质量——基于供需双侧机制的再检验(2011-2022年)

参照马红&#xff08;2023&#xff09;的做法&#xff0c;本团队对来自软科学《数字化转型与制造企业绿色创新质量—基于供需双侧机制的再检验》一文中的基准回归部分进行复刻 一、数据介绍 数据名称&#xff1a;数字化转型与制造企业绿色创新质量 参考期刊&#xff1a;《软…

yolov8学习笔记(二)模型训练

目录 yolov8的模型训练 1、制作数据集&#xff08;标记数据集&#xff09; 2、模型训练&#xff08;标记数据集、参数设置、跟踪模型随时间的性能变化&#xff09; 2.1、租服务器训练 2.2、加训练参数 2.3、看训练时的参数&#xff08;有条件&#xff0c;就使用TensorBoard&…

three中界面交互gui.js库的使用

gui.js库(可视化改变三维场景) dat.gui.js说白了就是一个前端js库&#xff0c;对HTML、CSS和JavaScript进行了封装&#xff0c;学习开发的时候&#xff0c;借助dat.gui.js可以快速创建控制三维场景的UI交互界面&#xff0c;你打开课件中案例源码体验一下就能感受到。 学习dat…

http协议基础与Apache的简单介绍

一、相关介绍&#xff1a; 互联网&#xff1a;是网络的网络&#xff0c;是所有类型网络的母集因特网&#xff1a;世界上最大的互联网网络。即因特网概念从属于互联网概念。习惯上&#xff0c;大家把连接在因特网上的计算机都成为主机。万维网&#xff1a;WWW&#xff08;world…

转前端了!!

大家好&#xff0c;我是冰河~~ 没错&#xff0c;为了更好的设计和开发分布式IM即时通讯系统&#xff0c;也为了让大家能够直观的体验到分布式IM即时通讯系统的功能&#xff0c;冰河开始转战前端了。也就是说&#xff0c;整个项目从需求立项到产品设计&#xff0c;从架构设计到…

跟着cherno手搓游戏引擎【25】封装2DRenderer,封装shader传参,自定义Texture

封装2DRenderer&#xff1a; Renderer.h: #include"ytpch.h" #include"Renderer.h" #include <Platform/OpenGL/OpenGLShader.h> #include"Renderer2D.h" namespace YOTO {Renderer::SceneData* Renderer::m_SceneData new Renderer::S…

【计算机网络】应用层自定义协议

自定义协议 一、为什么需要自定义协议&#xff1f;二、网络版计算器1. 基本要求2. 序列化和反序列化3. 代码实现&#xff08;1&#xff09;封装 socket&#xff08;2&#xff09;定制协议和序列化反序列化&#xff08;3&#xff09;客户端&#xff08;4&#xff09;计算器服务端…

【星海随笔】存储硬盘基础信息科普

市场上的磁盘分类有&#xff1a;IDE磁盘&#xff08;多用于PC机&#xff09;、SATA磁盘、SAS磁盘、SSD磁盘等 IDE 易于使用与价格低廉&#xff0c;问世后成为最为普及的磁盘接口。 速度慢、速度慢、速度慢。 ATA-7是ATA接口的最后一个版本&#xff0c;也叫ATA133。ATA133接口支…

MyBatis使⽤PageHelper(MySQL)

MyBatis使⽤PageHelper&#xff08;MySQL&#xff09; 一、 limit分⻚二、PageHelper插件第⼀步&#xff1a;引⼊依赖第⼆步&#xff1a;在mybatis-config.xml⽂件中配置插件第三步&#xff1a;编写Java代码第四步&#xff1a;格式化结果查看 三、SpringBoot3 集成 PageHelper …

【人脸朝向识别与分类预测】基于PNN神经网络

课题名称&#xff1a;基于PNN神经网络的人脸朝向识别分类 版本日期&#xff1a;2024-02-20 运行方式&#xff1a;直接运行PNN0503.m文件 代码获取方式&#xff1a;私信博主或 QQ:491052175 模型描述&#xff1a; 采集到一组人脸朝向不同角度时的图像&#xff0c;图像来自不…

CAS5.3使用JPA实现动态注册服务

cas同时支持cas协议和OAuth2协议,官方默认是通过扫描json文件的形式注册客户端服务,但是此种方式需要重启服务才能生效,此次我们将使用JPA来完美实现动态注册服务,如果不知道cas如何部署,可以擦看之前的文章 cas-client基于CAS协议客户端搭建-CSDN博客 cas-server5.3自定义密…