庖丁解牛-二叉树的遍历

news2024/11/13 7:56:26

庖丁解牛-二叉树的遍历

在这里插入图片描述

〇、前言

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.coloradmin.cn/o/1465436.html

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

相关文章

linux drm mipi dsi lcd 点屏之设备树配置

linux drm mipi dsi lcd 点屏之设备树配置 设备树文档&#xff1a; https://elixir.bootlin.com/linux/v6.8-rc5/source/Documentation/devicetree/bindings/display/dsi-controller.yaml https://elixir.bootlin.com/linux/v6.8-rc5/source/Documentation/devicetree/binding…

卫星地面站监测系统仿真

当今世界&#xff0c;大国竞争日趋激烈&#xff0c;国际关系愈发紧张&#xff0c;信息与通信已经是当下高度信息化社会的“命脉”&#xff0c;信息只有经过有效且广泛地传播&#xff0c;才能成为一种有利用价值的资源&#xff0c;产生经济效益、推动社会发展。通信技术在发展的…

C语言运用中断子系统用驱动控制led实验,c语言串口led点灯实验(驱动+应用层)

中断子系统用驱动控制led实验 驱动代码 #include <linux/init.h> #include <linux/module.h>#include<linux/interrupt.h> #include<linux/gpio.h> #include<linux/timer.h>#include<linux/of.h> #include<linux/of_irq.h> #inclu…

QQ防红跳转短网址生成网站完整源码

使用此源码可以生成QQ自动跳转到浏览器的短链接&#xff0c;无视QQ报毒&#xff0c;任意网址均可生成。 全新界面&#xff0c;网站背景图采用Bing随机壁纸 支持生成多种短链接 兼容电脑和手机页面 生成网址记录功能&#xff0c;域名黑名单功能 网站后台可管理数据 安装说明&am…

《图解HTTP》笔记2:http的构成

1&#xff0c;查看浏览器上面一个具体的http请求 浏览器地址栏输入网址&#xff1a;https://news.baidu.com/ 使用浏览器的开发者工具&#xff0c;查看网络中发送和接受的数据。 可以看到输入一个网址&#xff0c;浏览器和服务器进行了很多的交互。&#xff08;绿色部分&#…

【深蓝学院】移动机器人运动规划--第6章 模型预测控制(MPC)与运动规划--笔记

0. Outline 1. Reactive Control&#xff08;反应式控制&#xff09; 控制学中的 “Reactive Control” 通常指的是一种控制策略&#xff0c;它依赖于系统对特定事件或变化的即时反应&#xff0c;而不是按照预定的计划或策略行动。这种控制往往是基于当前的传感器输入来做出决…

盘点自动化汽车生产线设备 数据采集分析联合各设备

1.机器人自动装配线 机器人自动装配线已成为汽车制造业中的常见场景。这些机器人在汽车组装的各个环节发挥关键作用&#xff0c;从焊接和铆接到零部件组装。它们不仅提高了装配速度&#xff0c;还确保了产品的一致性&#xff0c;降低了废品率。 2.3D打印技术 3D打印技术正在汽车…

电商API接口接入|电子商务市场最简单的数据采集方法,你学到了吗?

小刘从某职业院校电子商务专业毕业后&#xff0c;-直在某品牌电商部负责运营工作&#xff0c;近期&#xff0c;同班同学小王邀请小刘加入创业大军&#xff0c;共同开设网店&#xff0c;销售家乡的螃蟹、鲜虾、扇贝等生鲜水产。 运营经验丰富的小刘决定&#xff0c;在创业开始前…

Jenkins的使用GIT(4)

Jenkins的使用GIT 20211002 我们使用 Jenkins 集成外部 Git 仓库&#xff0c;实现对真实代码的拉取和构建。在这里&#xff0c;我们选用 Coding/Github/Gitee 等都可以作为我们的代码源 1 生成公钥私钥 首先&#xff0c;我们先来配置公钥和私钥。这是 Jenkins 访问 Git 私有库…

mysql 事务详解一

前言 提到事务&#xff0c;大家肯定不陌生。在我们现实生活中也是存在的&#xff0c;比如我们去超市购物&#xff0c;然后去支付。虽然是两个步骤&#xff0c;必须保证同时成功&#xff0c;这个交易才可以完成。 如果这个场景&#xff0c;拿到我们购物系统&#xff0c;就是几…

智能高压森林应急消防泵|保障森林安全|深圳恒峰

随着科技的不断发展&#xff0c;我们的生活质量得到了显著提升。在森林保护领域&#xff0c;一项创新技术正在发挥着关键作用——智能高压森林应急消防泵。这种设备不仅提高了灭火效率&#xff0c;更为森林资源的安全保驾护航。 在过去&#xff0c;面对森林火灾&#xff0c;消防…

AIDL的工作原理与使用示例 跨进程通信 远程方法调用RPC

AIDL的介绍与使用 AIDL&#xff08;Android Interface Definition Language&#xff09;是Android中用于定义客户端和服务端之间通信接口的一种接口定义语言。它允许你定义客户端和服务的通信协议&#xff0c;用于在不同的进程间或同一进程的不同组件间进行数据传递。AIDL通过…

LDR6020芯片驱动未来:TYPE-C桌面显示器的新篇章

TYPE-C接口桌面显示器&#xff0c;与传统显示器截然不同。它不仅在视频传输方面表现出色&#xff0c;还融入了创新的充电功能。利用显示器的DC电源&#xff0c;可以轻松转换成PD协议&#xff0c;为笔记本、任天堂等HOST设备提供稳定的充电服务。 兼容性&#xff1a;连接无忧 …

redis GEO 类型原理及命令详解

目录 前言 一、GeoHash 的编码方法 二、Redis 操作GEO类型 前言 我们有一个需求是用户搜索附近的店铺&#xff0c;就是所谓的位置信息服务&#xff08;Location-Based Service&#xff0c;LBS&#xff09;的应用。这样的相关服务我们每天都在接触&#xff0c;用滴滴打车&am…

文件夹无法压缩是怎么回事?分享3种简单的方法~

在日常使用电脑的过程中&#xff0c;我们经常需要对文件夹进行压缩&#xff0c;以节省存储空间或方便传输。然而&#xff0c;有时候我们可能会遇到文件夹无法压缩的情况&#xff0c;这可能会让人感到困惑。本文将探讨文件夹无法压缩的原因&#xff0c;并提供解决方法&#xff0…

谷粒商城-nginx搭建域名访问环境性能压测

nginx搭建域名访问环境 正向代理与反向代理 正向代理&#xff1a;客户端向代理服务器发请求并指定目标服务器&#xff0c;代理向目标服务器转交请求并将获得的内容返回给客户端。 反向代理&#xff1a;用户直接访问反向代理服务器就可以获得目标服务器的资源。反向代理服务器…

基于EasyCVR视频汇聚系统的公安网视频联网共享视频云平台建设思路分析(二)

一、需求分析 随着科技的飞速发展&#xff0c;视频监控联网技术在公安工作中发挥着越来越重要的作用。为了提高公安部门对各类事件的响应速度和处理能力&#xff0c;建设一个高效、稳定的公安视频联网共享云平台显得尤为重要。通过建设开放的视频联网共享云平台&#xff0c;实…

Android相机调用-libusbCamera【外接摄像头】【USB摄像头】 【多摄像头预览】

有的自定义系统&#xff0c;对于自己外接的USB摄像头&#xff0c;android原生的camera和camera2都无法打开&#xff0c;CameraX也用不了。这时候就要用libusbCamera&#xff0c;这个库可以打开摄像头&#xff0c;还可以多摄像头同时预览。本文主要是同时打开3个USB摄像头的项目…

C语言第二十九弹---浮点数在内存中的存储

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 目录 1、浮点数在内存中的存储 1.1、练习 1.2、浮点数怎么转化为二进制 1.3、浮点数的存储 1.3.1、浮点数存的过程 1.3.2、浮点数取的过程 1.3、题目解析…

配置开机自启

进入任务计划程序 点击创建基本任务&#xff0c;按照向导一步一步进行下去