【Java】/* 二叉树 - 底层实现*/

news2024/11/16 9:16:37

一、前序遍历 - 递归

/* 1. 前序遍历 - 递归 */
    public void preOrder(TreeNode root) {
        //1. 如果根节点为null
        if (root == null) {
            return;
        }

        //本意:打印树的根,左,右节点

        //2. 打印根节点的值
        System.out.print(root.val + " ");
        //3. 如果root.left也有左,右节点...,
        //   我们直接使用sout打印root.left.val...会造成打印不全。
        //   既然子树也是树,那么我们可以利用方法的递归去处理
        preOrder(root.left);
        preOrder(root.right);
    }

二、中序遍历 - 递归

/* 2. 中序遍历 - 递归 */
    public void inOrder(TreeNode root) {
        //1. 如果根节点为null
        if (root == null) {
            return;
        }

        //本意:打印树的左,根,右节点

        //2. 如果root的左树也是一颗完整的树,
        //   此时直接打印root.left会造成打印不完全的现象
        //   既然如此,我们可以利用递归先打印root.left再打印当前树的根节点
        inOrder(root.left);
        //3. 打印根节点的值
        System.out.print(root.val + " ");
        //4. 打印root右树
        preOrder(root.right);
    }

 

三、后续遍历 - 递归

/* 3. 后续遍历 - 递归 */
    public void postOrder(TreeNode root) {
        //1. 如果根节点为null
        if (root == null) {
            return;
        }

        //本意:打印树的左,右,根节点

        //2. 如果root的左树也是一颗完整的树,
        //   此时直接打印root.left会造成打印不完全的现象
        //   既然如此,我们可以利用递归先打印root.left再打印当前树的右树和根节点
        postOrder(root.left);
        postOrder(root.right);
        //3. 打印根节点的值
        System.out.print(root.val + " ");
    }

【小结】:

1. 之所以用到递归是由于root的左树,右树也是一颗完整的树,想要打印完整得先采用递归打印root的左树,右树,而不是直接用sout打印root.left,root.right。

2. 通过画图分析可知,当发现一个节点A的left节点为null时,会返回,使得代码回退到节点A的栈帧中,继续执行后面的打印节点A的right节点的代码。

四、其他方法

package bagone;

import javax.management.relation.InvalidRoleInfoException;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: tangyuxiu
 * Date: 2024-08-26
 * Time: 18:43
 */
public class MyBinaryTree {
    /* 使用内部类来表示树的节点 */
    private static class TreeNode {
        char val;
        TreeNode left;
        TreeNode right;

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

    /* 1. 前序遍历 - 递归 */
    public void preOrder(TreeNode root) {
        //1. 如果根节点为null
        if (root == null) {
            return;
        }

        //本意:打印树的根,左,右节点

        //2. 打印根节点的值
        System.out.print(root.val + " ");
        //3. 如果root.left也有左,右节点...,
        //   我们直接使用sout打印root.left.val...会造成打印不全。
        //   既然子树也是树,那么我们可以利用方法的递归去处理
        preOrder(root.left);
        preOrder(root.right);
    }

    /* 2. 中序遍历 - 递归 */
    public void inOrder(TreeNode root) {
        //1. 如果根节点为null
        if (root == null) {
            return;
        }

        //本意:打印树的左,根,右节点

        //2. 如果root的左树也是一颗完整的树,
        //   此时直接打印root.left会造成打印不完全的现象
        //   既然如此,我们可以利用递归先打印root.left再打印当前树的根节点
        inOrder(root.left);
        //3. 打印根节点的值
        System.out.print(root.val + " ");
        //4. 打印root右树
        preOrder(root.right);
    }

    /* 3. 后续遍历 - 递归 */
    public void postOrder(TreeNode root) {
        //1. 如果根节点为null
        if (root == null) {
            return;
        }

        //本意:打印树的左,右,根节点

        //2. 如果root的左树也是一颗完整的树,
        //   此时直接打印root.left会造成打印不完全的现象
        //   既然如此,我们可以利用递归先打印root.left再打印当前树的右树和根节点
        postOrder(root.left);
        postOrder(root.right);
        //3. 打印根节点的值
        System.out.print(root.val + " ");
    }

    /* 4. 树的节点个数 - 子问题思路 */
    public int size(TreeNode root) {
        //1. 如果根节点为null
        if (root == null) {
            return 0;
        }

        //2. 根节点1 + 左树节点个数 + 右树节点数
        return 1 + size(root.left) + size(root.right);
    }

    /* 4. 树的节点个数 - 遍历思路 */
    public int sizeTreeNode;
    public void sizeTwo(TreeNode root) {
        //1. 如果根节点为null
        if (root == null) {
            return;
        }

        //本质:遍历树的根,左,右如果不为空sizeTreeNode的值就++

        //2. 根节点算一个所以++
        sizeTreeNode++;

        //3. root的左树,右树节点个数
        //   这里不可能直接下成判断不为null后sizeTreeNode的值就++
        //   因为root的左,右节点也是一颗树,下列代码中不接收返回值,
        //   或着说size方法的返回值为什么要定义成void是因为,我们已经定义了成员变量去记录成员个数了
        //   不用多此一举
        size(root.left);
        size(root.right);
    }

    /* 5. 获取叶子节点的个数 - 子问题思路 */
    public int getLeafNodeCount(TreeNode root) {
        //1. 如果根节点为null
        if (root == null) {
            return 0;
        }

        //2. 如果根节点的左右子树都为null
        if (root.left == null && root.right == null) {
            return 1;
        }

        //3. 收集左树,右树的叶子节点个数
        return getLeafNodeCount(root.left) + getLeafNodeCount(root.right);
    }

    /* 5. 获取叶子节点的个数 - 遍历思路 */
    public int sizeLeafNode;
    public void getLeafNodeCountTwo(TreeNode root) {
        //1. 如果根节点为null
        if (root == null) {
            return;
        }

        //2. 如果根节点的左右子树都为null
        if (root.left == null && root.right == null) {
            sizeLeafNode++;
        }

        //3. 收集左树,右树的叶子节点个数
        getLeafNodeCount(root.left);
        getLeafNodeCount(root.right);
    }

    /* 6. 获取第K层节点的个数 */
    public int getKLevelNodeCount(TreeNode root, int k) {
        //条件:所给的k一定是合法的
        //1. 如果根节点为null(递归的过程中也会出现root为null的情况)
        if (root == null) {
            return 0;
        }

        //2. k == 1
        if (k == 1) {
            return 1;
        }

        //3. 求root的左树,右树的第k-1层
        return getKLevelNodeCount(root.left, k - 1) + getKLevelNodeCount(root.right, k - 1);
    }

    /* 7. 获取二叉树的高度 */
    public int getHeight(TreeNode root) {
        //1. 如果根节点为null
        if (root == null) {
            return 0;
        }

        // 核心:一棵树的高度等于,左树右树相比较的高度max + 1

        int hightOne = getHeight(root.left);
        int hightTwo = getHeight(root.right);
        return Math.max(hightOne,hightTwo) + 1;
    }

    /* 8. 检测值为value的元素是否存在 */
    public TreeNode find(TreeNode root, char val) {
        //1. 如果根节点为null
        if (root == null) {
            return root;
        }

        //2. 判断根节点的值是否为val
        if (root.val == val) {
            return root;
        }

        //3. root的左树,右树,是否存在val值
        TreeNode valNode = find(root.left, val);
        if (valNode != null) {
            return valNode;
        }

        valNode = find(root.right, val);
        //4. 不管是否为null,直接返回valNode中的值即可
        return valNode;
    }
}

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

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

相关文章

X86 PVE 下安装路由存储系统iStoreOS

简介 iStoreOS是一个比较易用的路由存储系统,它能让你获得更好的网络及 存储的体验。 系统本身开源免费,目前系统代码开源在:Github iStoreOS 下载固件 固件下载:https://fw.koolcenter.com/iStoreOS/x86_64/ istoreos-22.03.7…

数据结构——顺序表和单链表

数据结构 基本概念: 数据结构是一门研究如何有效组织数据,并提高数据处理效率的学科。通过研究各种数据内部的逻辑关系,使用某种特定的存储形式,并在此基础上对数据实施各种操作,这些工作被称为称为广义上的算法。 …

盈利47亿,快手的危机感却没消失

文丨郭梦仪 又是一年互联网大厂的半年报成绩单放榜时,一批主打下沉市场的公司也在从追求高增长,转向了高利润。 8月20日盘后,快手发布了“营利双增”的业绩报告,但显然营收增长远远低于利润的增长。 伴随着与抖音停战&#xff…

选择排序【详解】

本期介绍🍖 主要介绍:排序中的选择排序。 文章目录 1. 前言2. 选择排序3. 优化选择排序 1. 前言 相信只要接触过C语言的同学都或多或少了解排序问题,其中最基本,且最为人所熟知的排序是:选择排序。下面我会带着大家重新…

深入解读LLaMA-Factory

转自:老朱读AI 1、介绍 LLaMA-Factory是一个开源平台,旨在为研究人员和开发者提供便捷的大型语言模型微调环境。通过LLaMA-Factory,用户可以轻松地加载预训练模型,调整模型参数,并在特定数据集上进行训练&#xff0c…

【Python机器学习】NLP分词——利用分词器构建词汇表(六)——词汇表归一化

目录 大小写转换 词干还原 词形归并 使用场景 词汇表大小对NLP流水线的性能有很大的影响,有一种减少词汇表大小的方法是将词汇表归一化以便意义相似的词条归并成单个归一化的形式。这样做一方面可以减少需要再词汇表中保留的词条数,另一方面也会提高…

记录|Visual Studio中的Git上传下载使用

目录 前言一、前提准备Step1 仓库准备Step2. 本地仓库和远程仓库绑定当前效果展示 二、下载更新内容到本地仓库情形Step1. 下载 三、更新内容,上传文件到远程仓库情形Step1. 下载Step2. 上传当前效果展示 更新时间 前言 这部分是使用过程中的经验 一、前提准备 St…

【数模资料包】最新数模国赛word+latex模版|数模常用的算法python+matlab代码

【2024最全国赛研赛数模资料包】C君珍贵国一数模资料|最新数模国赛wordlatex模版|数模常用的算法pythonmatlab代码 国赛指:高教社杯全国大学生数学建模竞赛,研赛指:华为杯研究生数学建模竞赛。资料内容具体看文末卡片…

【C++算法/学习】位运算详解

✨ 忍能对面不相识,仰面欲语泪现流 🌏 📃个人主页:island1314 🔥个人专栏:算法学习 🚀 欢迎关注:👍点赞 &…

【Python 千题 —— 基础篇】面积计算(多种图形面积计算)

Python 千题持续更新中 …… 脑图地址 👉:⭐https://twilight-fanyi.gitee.io/mind-map/Python千题.html⭐ 题目描述 题目描述 编写一个面向对象的程序,定义一个基类 Shape 和两个派生类 Circle 和 Rectangle,用来计算不同图形…

原子操作与锁

1 原子性 1.1 CPU缓存 L1、L2:一级缓存、二级缓存,均为核心独有 L3:三级缓存,多个核心共用 多级缓存,弥补CPU与内存速度不匹配的问题 1.2 cache line 缓存进行管理的一个最小存储单元,缓存块 1.3 CPU读…

【xilinx】解决 I/O 时钟布局器错误:CLOCK_DEDICATED_ROUTE 异常示例

问题描述 设备&#xff1a; xcvm1102-sfva784-2HP-iS问题&#xff1a;尽管使用 GCIO 引脚作为时钟&#xff0c;但布局器返回 I/O 时钟错误 错误&#xff1a; <span style"background-color:#f3f3f3"><span style"color:#333333"><code&g…

《机器学习》 贝叶斯分类器 原理、参数讲解及代码演示

目录 一、贝叶斯算法 1、简介 2、贝叶斯算法具有以下特点&#xff1a; 二、贝叶斯原理 1、正向概率&#xff08;先验概率&#xff09; 例如&#xff1a; 2、逆向概率&#xff08;后验概率&#xff09; 3、公式 1&#xff09;实例1 2&#xff09;实例2 • 目标&#x…

基于初始运行数据的电池循环寿命预测

这个例子展示了如何使用线性回归(一种监督机器学习算法)预测快速充电锂离子电池的剩余循环寿命。使用基于物理的建模方法预测锂离子电池的循环寿命是非常复杂的&#xff0c;因为不同的操作条件和显著的设备可变性&#xff0c;即使是来自同一制造商的电池。对于这种情况&#xf…

FPGA上板项目(四)——FIFO测试

目录 实验内容实验原理FIFO IP 核时序绘制HDL 代码仿真综合实现上板测试 实验内容 理解 FIFO 原理调用 FIFO IP 核完成数据读写 实验原理 FIFO&#xff1a;First In First Out&#xff0c;先入先出式数据缓冲器&#xff0c;用来实现数据先入先出的读写方式。可分类为同步 FI…

论文翻译 | 通过逻辑增强大型语言模型中的零样本思维链推理

摘要 大型语言模型的最新进展已经展示了它们在各个领域的卓越泛化性。然而&#xff0c;他们的推理能力仍有很大的提高空间&#xff0c;特别是在面对需要多步骤推理的场景时。虽然大型语言模型拥有广泛的知识&#xff0c;但它们的推理往往不能有效地利用这些知识来建立连贯的思维…

机器学习/数据分析--通俗语言带你入门决策树(结合分类和回归案例)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 机器学习是深度学习和数据分析的基础&#xff0c;接下来将更新常见的机器学习算法注意&#xff1a;在打数学建模比赛中&#xff0c;机器学习用的也很多&a…

[LeetCode]根据决策树设计代码解决dfs

目录 46. 全排列 - 力扣&#xff08;LeetCode&#xff09; 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 46. 全排列 - 力扣&#xff08;LeetCode&#xff09; 决策树&#xff1a;根据题意可以知道&#xff0c;全排列需要找到数组内元素不重复的所有排列方式&#xff0c…

Java面向接口编程——开发打印机

题目&#xff1a; 墨盒&#xff1a;彩色、黑白 纸张类型&#xff1a;A4、B5 墨盒和纸张都不是打印机厂商提供的 打印机厂商要兼容市场上的墨盒、纸张 墨盒接口&#xff1a; public interface InkBox {String colorInkBox(); // 墨盒颜色} 纸张接口&#xff1a; public i…

Centos 添加双网卡 (生产环境配置记录)

1、在虚拟机中添加网卡2 [rootntpserver network-scripts]# ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo …