数据结构之初始二叉树(2)

找往期文章包括但不限于本期文章中不懂的知识点:

个人主页:我要学编程(ಥ_ಥ)-CSDN博客

所属专栏:数据结构(Java版)

二叉树的前置知识(概念、性质、、遍历)

通过上篇文章的学习,我们已经知道什么是二叉树,以及其性质和遍历的方式了。接下来主要是实现代码。

目录

伪创建二叉树

遍历二叉树 

获取二叉树中节点的个数 

获取二叉树中叶子节点的个数

获取二叉树中第K层节点的个数

获取二叉树的高度 

在二叉树中找寻元素 


伪创建二叉树

为啥叫伪创建二叉树呢?因为我们现在才刚开始学习二叉树,而创建二叉树是一个非常复杂的过程(树的递归定义的)。因此我们就先手动的来创建二叉树。树是有一个一个的结点组成,因此得先把结点创建出来。树的结点我们采用的是简单的孩子表示法:

    // 树的结点
    static class TreeNode {
        public char val; // 数据域
        public TreeNode left; // 左子树
        public TreeNode right; // 右子树

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

创建的二叉树图形如下:

    public TreeNode createBinaryTree() {
        TreeNode A = new TreeNode('A');
        TreeNode B = new TreeNode('B');
        TreeNode C = new TreeNode('C');
        TreeNode D = new TreeNode('D');
        TreeNode E = new TreeNode('E');
        TreeNode F = new TreeNode('F');
        TreeNode G = new TreeNode('G');
        // 根据图形关系把结点之间相连
        A.left = B;
        A.right = C;
        B.left = D;
        B.right = E;
        C.left = F;
        C.right = G;
        // 返回根结点
        return A;
    }

遍历二叉树 

二叉树创建完成后,我们就可以遍历打印二叉树,看看是否符合我们的预期结果。遍历的四种方式,我们前面也学习了。

前序遍历: 

    // 前序遍历
    public void preOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        // 打印根结点的值
        System.out.print(root.val+" ");
        // 递归遍历根的左子树
        preOrder(root.left);
        // 递归遍历根的右子树
        preOrder(root.right);
    }

递归的限制条件:当递归到 root 为 null 时,就开始回退。随着递归的深入,root 不断的接近 null。

中序遍历:

    // 中序遍历
    public void inOrder(TreeNode root) {
        // 中序遍历:左子树->根->右子树
        if (root == null) {
            return;
        }
        // 递归遍历根的左子树
        inOrder(root.left);
        // 打印根结点的值
        System.out.print(root.val+" ");
        // 递归遍历根的右子树
        inOrder(root.right);
    }

后序遍历:

    // 后序遍历
    public void postOrder(TreeNode root) {
        // 后序遍历:左子树->右子树->根
        if (root == null) {
            return;
        }
        // 递归遍历根的左子树
        postOrder(root.left);
        // 递归遍历根的右子树
        postOrder(root.right);
        // 打印根结点的值
        System.out.print(root.val+" ");
    }

由于层序遍历还是比较复杂,因此我们后面再学习。

获取二叉树中节点的个数 

思路一:这个同样是遍历二叉树,遇到不为空的结点就++,最后统计的就是树的节点个数。

    // 记录节点个数
    public int treeNodeSize; 
    public void size(TreeNode root) {
        if (root == null) {
            return;
        }
        // 根结点
        treeNodeSize++;
        // 左子树
        size2(root.left);
        // 右子树
        size2(root.right);
    }

思路二:整棵树的节点个数等于 根结点+左子树的节点个数+右子树的节点个数

    // 获取树中节点的个数
    public int size(TreeNode root) {
        if (root == null) {
            return 0;
        }
        // 左子树的节点个数+右子树的节点个数+根结点
        return size(root.left)+size(root.right)+1;
    }

思路一采用的是遍历的方式,思路二采用的是化为子问题的方式。思路二也是更加接近递归的方式。

获取二叉树中叶子节点的个数

思路:首先,我们得知道什么是叶子节点。叶子结点的特点是其左孩子和右孩子都是null。同样这也是采用遍历的方式。

法一:采用子问题思路

    // 获取叶子节点的个数
    public int getLeafNodeCount(TreeNode root) {
        if (root == null) {
            return 0;
        }
        // 遇到叶子结点就返回1
        if (root.left == null && root.right == null) {
            return 1;
        }
        // 返回左子树的叶子节点个数+右子树的叶子节点个数
        return getLeafNodeCount(root.left) + getLeafNodeCount(root.right);
    }

法二:采用遍历思路

    public int leafSize;
    public void getLeafNodeCount(TreeNode root) {
        if (root == null) {
            return;
        }
        if (root.left == null && root.right == null) {
            leafSize++;
        }
        // 遍历左子谁
        getLeafNodeCount2(root.left);
        // 遍历右子树
        getLeafNodeCount2(root.right);
    }

获取二叉树中第K层节点的个数

上面是对于第K层的介绍,根结点是作为第一层。 

思路:当K为1时,就可以直接返回这一层的节点个数即可。因此我们就是要递归到K不断的接近1.

法一: 采用子问题思路

    // 获取第K层节点的个数
    public int getKLevelNodeCount(TreeNode root, int k) {
        // 假定不存在K无效的情况
        if (root == null) {
            return 0;
        }
        if (k == 1) {
            return 1;
        }
        // 左子树的第k-1层的节点个数+右子树的第k-1层的节点个数
        return getKLevelNodeCount(root.left, k-1) +
                getKLevelNodeCount(root.right, k-1);
    }

法二: 采用遍历思路

    public int getLevelNodeSize;
    public void getKLevelNodeCount(TreeNode root, int k) {
        // 假定不存在K无效的情况
        if (root == null) {
            return;
        }
        if (k == 1) {
            getLevelNodeSize++;
        }
        // 遍历左子树的第k-1层
        getKLevelNodeCount2(root.left, k-1);
        // 遍历右子树的第k-1层
        getKLevelNodeCount2(root.right, k-1);
    }

获取二叉树的高度 

思路:获取二叉树的高度和求第K层节点的个数类似。同样根结点算高度为1。接着就是分别递归计算左子树和右子树的高度的最大值。

采用子问题思路

    // 获取二叉树的高度
    public int getHeight(TreeNode root) {
        if (root == null) {
            return 0;
        }
        // 左子树与右子树的最大高度+根结点
        return Math.max(getHeight(root.left), getHeight(root.right)) + 1;
    }

这个如果不采用子问题思路,而是用遍历思路的话,只能用层序遍历来写,又因为层序遍历过于复杂,因此我们暂时先不写这个代码。

在二叉树中找寻元素 

 思路:这个比较简单,就是遍历去比较即可。

    // 检测值为value的元素是否存在
    public TreeNode find(TreeNode root, int val) {
        if (root == null) {
            return null;
        }
        // 采用前序遍历的方式:根->左子树->右子树
        // 根
        if (root.val == val) {
            return root;
        }
        // 在左子树中寻找,肯定有一个结果
        TreeNode findLeft = find(root.left, val);
        // 如果不为null,则说明找到了
        if (findLeft != null) {
            return findLeft;
        }
        // 在右子树中寻找,肯定有一个结果,不管结果如何直接返回即可
        return find(root.right, val);
    }

注意:这里在寻找二叉树中的节点时,采用前序遍历的方式是最有效率的。因为前序遍历是首先比较根结点,而我们就是需要比较根结点。 

对于二叉树的基本操作我们就已经学习完了。基于上述基本操作就可以进行一些简单的刷题了,后续也会在刷题中继续完善二叉树的相关操作。

好啦!本期 数据结构之初始二叉树(2)的学习之旅就到此结束啦!我们下一期再一起学习吧!

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

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

相关文章

STM32第十八课:SPIFlash

目录 需求一、SPI概要二、SPI配置1.开时钟2.配置IO3.配置&使能SPI 三、FLash操作函数1.SPI发送数据2.FLASH写使能3.FLASH等待操作完成4.FLASH页写操作5.FLASH读操作6.FLASH扇区擦除 四、需求实现 需求 通过SPI控制FLash进行数据的保存和删除。 一、SPI概要 在我们使用UA…

oracle控制文件详解以及新增控制文件

文章目录 oracle控制文件1、 控制文件包含的主要信息如下:2、查看目前系统的控制文件信息,主要是查看相关的字典视图 oracle新增控制文件 oracle控制文件 控制文件是一个很小的二进制文件(10MB左右),含有数据库结构信息,包括数据…

(leetcode学习)15. 三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意:答案中不可以包含重复的三元组。 示例 1&a…

浅谈全量微调和PEFT高效微调(LoRA)

浅谈全量微调和LoRA微调 全量微调Full Fine-Tuning 全量微调是指在预训练的大型模型基础上调整所有层和参数,‌使其适应特定任务的过程。‌这一过程使用较小的学习率和特定任务的数据进行,‌可以充分利用预训练模型的通用特征 高效微调 高效微调&…

PyQt5图形界面--基础笔记

from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QToolTip, QLabel, QLineEdit from PyQt5.QtGui import QIcon, QFont, QPixmap import sys https://www.bitbug.net/ 将图片转换为ico格式, 用来更改打包的文件图标 -F 只产生exe文件, 其他临时文件不产生 -…

深度学习论文: XFeat: Accelerated Features for Lightweight Image Matching

深度学习论文: XFeat: Accelerated Features for Lightweight Image Matching XFeat: Accelerated Features for Lightweight Image Matching PDF:https://arxiv.org/pdf/2404.19174 PyTorch: https://github.com/shanglianlm0525/PyTorch-Networks 1 概述 本文创新性地推出了…

kubernetes——Istio(三)

一、安全 将单一应用程序分解为微服务可提供各种好处,包括更好的灵活性、 可伸缩性以及服务复用的能力。但是,微服务也有特殊的安全需求: 为了抵御中间人攻击,需要流量加密。为了提供灵活的服务访问控制,需要双向 TL…

大语言模型可以处理图问题吗?

为了探讨大型语言模型(LLM)在处理自然语言描述的图结构问题上的能力,提出了NLGraph基准测试集,包含29,370个涉及不同复杂度的图推理任务。这些任务从简单的连通性和最短路径到复杂的最大流和图神经网络模拟。评估结果显示&#xf…

【C语言初阶】探索编程基础:深入理解分支与循环语句的奥秘

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C语言 “ 登神长阶 ” 🤡往期回顾🤡:C语言入门 🌹🌹期待您的关注 🌹🌹 ❀分支与循环语句 📒1.…

uniapp-day2

目录 1.在uniapp中显示视图有三种方式 2.scss和less的区别? 1. 语法差异 2. 变量和常量 3. 嵌套规则 4. 混合(Mixins) 5. 继承和扩展 6. 注释 7. 导入其他文件 8. 生态系统和社区支持 9. 其他特性 3.新建页面:要在page…

Transformer模型:scaled self-attention mask实现

前言 视频链接:20、Transformer模型Decoder原理精讲及其PyTorch逐行实现_哔哩哔哩_bilibili 文章链接:Transformer模型:WordEmbedding实现-CSDN博客 Transformer模型:Postion Embedding实现-CSDN博客 Transformer模型&#xff…

一文读懂近场通信NFC

近场通信(Near Field Communication,简称NFC),NFC是在非接触式射频识别(RFID)技术的基础上,结合无线互连技术研发而成. 是一种新兴的技术,使用了NFC技术的设备(例如移动电话)可以在彼…

基于vite的vue脚手架工具整合:ts、jsx、eslint、prettier、stylelint、tailwind...

为了帮助vue新手更高效的学习vue3的基础知识、组件开发以及项目方案整合,小卷给大家整理了一个10分钟搞定《基于vite的vue脚手架工具整合》的教程。所有工具都是目前最新的版本,实践和调试过,没有一行多余的配置。

数据库基本查询(表的增删查改)

一、增加 1、添加信息 insert 语法 insert into table_name (列名) values (列数据1,列数据2,列数据3...) 若插入时主键或唯一键冲突就无法插入。 但如果我们就是要修改一列信息也可以用insert insert into table_name (列名) values (列数据1&am…

【JVM基础03】——组成-详细介绍下Java中的堆

目录 1- 引言:堆1-1 堆是什么?(What)1-2 为什么用堆?堆的作用 (Why) 2- ⭐核心:堆的原理(How)2-1 堆的划分2-2 Java 7 与 Java 8 的堆区别 3- 小结:3-1 详细介绍下Java的堆?3-2 JVM …

FPGA:基于复旦微FMQL10S400 /FMQL20S400 国产化核心板

复旦微电子是国内集成电路设计行业的领军企业之一,早在2000年就在香港创业板上市,成为行业内首家上市公司。公司的RFID芯片、智能卡芯片、EEPROM、智能电表MCU等多种产品在市场上的占有率位居行业前列。 今天介绍的是搭载复旦微 FMQL10S400/FMQL20S400的…

Python从0到100(三十九):数据提取之正则(文末免费送书)

前言: 零基础学Python:Python从0到100最新最全教程。 想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…

前端框架学习之 搭建vue2的环境 书写案例并分析

目录 搭建vue的环境 Hello小案例 分析案例 搭建vue的环境 官方指南假设你已经了解关于HTML CSS 和JavaScript的中级知识 如果你刚开始学习前端开发 将框架作为你的第一步可能不是最好的主意 掌握好基础知识再来吧 之前有其他框架的使用经验会有帮助 但这不是必需的 最…

基于双向长短时记忆神经网络(Bi-LSTM)的数据回归预测

代码原理 1.循环神经网络 循环神经网络(Recurrent Neural Network, RNN) 是深度学习领域一类具有内部自连接的神经网络能够学习复杂的矢量到矢量的映射。一个简单的循环神经网络结构,其结构包含三部分,分别为输入层、隐藏层和输出层,如图1所…

元器件基础学习笔记——磁珠

一、磁珠的作用及构造 1.1 磁珠的作用 磁珠是一种用于抑制高频噪声的被动电子组件,通常由铁氧体材料制成,这种材料具有高电阻率和高磁导率,使其能够在高频下有效地将干扰信号以热能的形式消耗掉。在电路设计中,磁珠被广泛用于信号…