颠沛流离学二叉树(完结撒花篇)

news2025/3/18 13:39:35

本篇会加入个人的所谓鱼式疯言

❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言

而是理解过并总结出来通俗易懂的大白话,

小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.

🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!

在这里插入图片描述

前言

在上两篇 二叉树系列 的文章中,我们学习了二叉树的 概念特性遍历方式 , 而在本篇文章中,将展开对 二叉树其他基本核心操作 的详解 ❤️ ❤️ ❤️ ❤️

提前透露一下哦, 本篇文章的基本操作,小编都会带着大家用 递归非递归 的代码带着大家走一遍哦 💖 💖 💖 💖

目录

  1. 获取树中节点的个数

  2. 获取叶子节点的个数

  3. 获取第 K 层的节点的个数

  4. 获取二叉树的高度(最大深度)

  5. 查找 节点的值等于的 value 的节点

  6. 判断一棵树是否是完全二叉树

一. 获取树中节点的个数

1. 操作分析

由于我们的二叉树是分为 两边的,分别是 左子树右子树 , 要求树中的节点,我们就需要知道 左子树的节点右子树的节点 ,最后加上自身的 1个根节点

在这里插入图片描述

2. 代码实现

<1>. 递归实现

// 递归计算节点个数
public int Size(TreeNode root) {
    if (root==null) {
        return 0;
    }

    return Size(root.left)+1+Size(root.right);
}

递归的代码实现,就是咱们 动画上的执行过程 了,小编在这里就不赘述了 💞 💞 💞 💞

动画展示

请添加图片描述

在这里插入图片描述

<2>. 非递归实现



// 非递归遍历节点个数
   public int nodeSize;

    public void setNodeSize(TreeNode root) {
        if (root==null) {
            return;
        }

        // 只要遍历过的节点
        // 就让 节点数 ++
        nodeSize++;


        // 先遍历左子树
        setNodeSize(root.left);

        // 遍历右子树
        setNodeSize(root.right);
    }
    

在这里插入图片描述

非递归的执行过程 :

我们这里利用了 前序遍历 的思路, 当我们每走过一个节点,就让我们的 nodeSize++

当完全的走过 每一个节点 , 我们 的 nodeSize 就加多少次

当我们遍历完 整个二叉树 , 也就统计出二叉树 所有的节点

鱼式疯言

关于求树中接节点个数的操作,小编最大的体会就是 子问题递归思路

由于我们 递归 的是不断把 每一个节点重新看成是根节点 的思路

所以我们只需要求出每个根节点的个数。所累积的个数,不就是我们的 节点总数 吗 ! ! !

这就是 子问题 的思路, 小伙伴在思考这一类问题时,一定要学会把一个 大问题 拆分成我们能解决的 一个一个小问题 的思想.

二. 获取叶子节点的个数

1. 操作分析

小伙伴都知道我们 二叉树的叶子节点 的定义,就是 度为0 的节点

那么我们该怎么找 度为零 的节点呢 💞 💞 💞 💞

其实很简单,我们只需要返回 左右子树所有节点 同时 左节点右子树 也为 null

最后 左右子树的叶子节点相加 即可

在这里插入图片描述

2. 代码实现

<1>. 递归实现

// 递归计算叶子个数
public int leafSize(TreeNode root) {
    if (root==null) {
        return 0;
    }

    if (root.left==null && root.right==null) {
        return 1;
    }

    return leafSize(root.left)+leafSize(root.right);
}

在这里插入图片描述

关于 递归实现 的执行步骤,下面就让小编用 动画 的形式来描述吧 😊 😊 😊 😊

动画展示

请添加图片描述

<2>. 非递归实现


 public int leafSize;


  // 非递归求叶子节点的个数
    public void setLeafSize(TreeNode root) {
        if (root==null) {
            return;
        }

        // 如果左右节点为 null
        // 就是我们需要的节点
        if (root.right==null && root.left==null) {
            leafSize++;
        }

        // 遍历左子树
        setLeafSize(root.left);

        // 遍历右子树
        setLeafSize(root.right);
    }

  

在这里插入图片描述

非递归的实现过程

非递归的根本是依赖于 我们的遍历 来实现的,当遍历到某个 左节点为 null 并且 右节点也为 null 时, 就令 leafSize ++

当遍历完整个 二叉树的所有节点,也就意味着 所有的叶子节点 已经被 leafSize 统计完了

鱼式疯言

对于 递归实现 的思路来说,我们还是用 子问题 的思路,把一棵树拆成 多颗子树

子树 又成为 新的树, 在新的树里面去寻找 左右子树都为null 的节点 ,

最终回归到 最开始的整棵树 上解决该问题 ! ! !

三. 获取第 K 层的节点的个数

1. 操作分析

要得到 第 K 层的节点 , 不免想起我们上一篇文章中所用的 层序遍历 的思想, 每一层也就相当于 二维数组中的每一行

所有要得到 每一层的节点数 ,本质上就是当我们 递归往下递的每走一行的 左子树和右子树 , k 就 减去一行 。

最终 当 K = 1 时, 就回退到 整棵树的根节点 ,就是我们要 获取到 第 K 层的节点个数

在这里插入图片描述

2. 代码实现

 // 求树某深度的节点数
    public int treeIndexlength(TreeNode root , int key) {
        // 如果节点为 null 返回 0
        if (root==null) {
            return 0;
        }

        /**
         *
         * 当 k = 1 时 就意味着到底最后一层
         * 返回当前根节点即可
         *
         *
         *
         */

        // 如果 这个位置 没有左右
        if (key==1) {
            return 1;
        }


        /**
         * 先统计左边的节点
         *
         * 再统计右边的节点
         *
         * 最后都要减少 key 次
         * 代表统计了一层
         *
         * 也就是说每统计一层 ,就减少一层
         *
         */

        //
        int left = treeIndexlength(root.left,key-1);

        // 再统计右边的节点
        int right = treeIndexlength(root.right,key-1);



        // 一直返回该 key 位置的节点
        return left+right;
    }

在这里插入图片描述

具体 递归的过程 我们通过下面动画展示:请添加图片描述

鱼式疯言

扩展一下

小伙伴有没有想到一个点:

   // 一直返回该 key 位置的节点
    return left+right;

我们这边是 直接返回 left + right 是得到我们当前 第k层 深度的节点数

但如果我们

 return left+right + 1;  

我们如果是 + 1 呢?

答案就是返回 从整棵树的根节点第k层所有节点总和

感兴趣的小伙伴可以自己 研究 哦, 小编在这里就不细讲了 💖 💖 💖 💖**(代码如下)**

// 求树某深度的到根节点所有节点数
public int treeIndexSize(TreeNode root , int key) {
    if (root==null) {
        return 0;
    }

    if (key==1) {
        return 1;
    }


    int left=treeIndexSize(root.left,key-1);


    int right=treeIndexSize(root.right,key-1);


    // key 位置开始查找节点 并 一直累加
    return left+right+1;
}

四.获取树的高度(最大深度)

1. 操作分析

要获取高度小伙伴们先得理解高度该怎么来, 我们可以设想一下,

如果一颗树的左子树高度为 3 右子树的高度为 4 , 那么 这颗树的高度是 3 还是 4

很显然 这都 不对

树的高度最终应该是 5 才对, 因为啊, 我们树的高度是 左右子树中较高的那个高度 再 + 上自身根节点的高度 1 , 所以我们得到的树的高度是 4 + 1 才对

在这里插入图片描述

2. 代码实现

// 返回树的最大深度
public int treeHeight(TreeNode root) {
    if (root==null) {
        return 0;
    }

    // 求左子树的深度
    int leftnum=treeHeight(root.left);

    // 求右子树的深度
    int rightnum=treeHeight(root.right);

    /**
     * 根据左右子树两边的高度
     *
     * 哪边高 取 哪边
     *  最后还要加上该节点的高度
     *
     */


    return leftnum>rightnum? leftnum+1: rightnum+1;
}

在这里插入图片描述

具体我们由于递归不好描述,请小伙伴们看动画分析递归的全过程哦 💫 💫 💫 💫

动画展示

请添加图片描述

鱼式疯言

当我们用 子问题 的思路 在 寻找数的高度 的关键在于我们要注意加上不仅要比较 两端左子树右子树高度, 那个自身的 根节点的 1 也要同时加上

五. 查找节点的值等于的 value 的节点

1. 操作分析

查找某个等于 val 的值, 我们就需要在 遍历的基础上 完成

所以我们只需要考虑 一点 即可,当我们在遍历过程

如果 左子树或者右子树 的节点的 val 找到了等于 val 就返回该 节点 , 如果没找到就返回 null .

在这里插入图片描述

2. 代码实现

// 查找节点
    public TreeNode find(TreeNode root, char val) {
        if(root==null) {
            return null;
        }



        // 判断新的根节点的 val 是否 等于目标值 val
        if (Character.compare(val,root.val)==0) {
            return  root;
        }


        // 在左子树中查找该节点
        TreeNode node1=  find(root.left,val);

        // 一旦找到就返回该节点
        if (node1 !=null) {
            return node1;
        }

        // 在右子树中查找该今节点
        TreeNode node2= find(root.right,val);

        // 一点找到就返回该节点
        if (node2 !=null) {
            return node2;
        }

        // 都没有找到就返回 null
       return  null;

    }

在这里插入图片描述

下面我们看看动画对于这段代码的理解吧 🤔 🤔 🤔 🤔

动画展示

请添加图片描述

鱼式疯言

细节处理:

   // 在左子树中查找该节点
    TreeNode node1=  find(root.left,val);

    // 一旦找到就返回该节点
    if (node1 !=null) {
        return node1;
    }

    // 在右子树中查找该今节点
    TreeNode node2= find(root.right,val);

    // 一点找到就返回该节点
    if (node2 !=null) {
        return node2;
    }

我想肯定有小伙伴会直接返回 node1 或者 node2 的值, 而不加判断, 这样做是不是有点问题呢 ???

是的,是有些问题,小伙伴应该知道如果我们先 递归左子树 或者 右子树 来达到遍历的效果, 一但 左子树没有找到该 val目标值 ,就会去右边的 右子树

p但我们 中途一旦返回,就会陷入只找寻 左边一个节点 ,然后就直接返回了,未达到遍历的效果 , 也就更不可能找到我们的 val 值了

六. 判断一棵树是否是完全二叉树

1. 操作分析

要考虑是否是完全二叉树,我们只需要考虑一点即可:

左子树 < 右子树高度 : 用 -1 来标记,代表 不是完全二叉树

左子树 >= 右子树高度: 就返回该高度

在这里插入图片描述

2. 代码实现

/**
     * 检查左子树和右子树的高度关系
     * 
     * 当左子树 > 右子树时 ,就不是完全二叉树
     * 否则就是完全二叉树
     * @param root 根节点
     * @return 返回布尔类型
     * 
     */

    private int CheckTreeCount(TreeNode root) {
       if (root==null) {
           return  0;
       }

       int left=CheckTreeCount(root.left);

        /**
         * 当此树不是完全二叉树的就返回 负数
         * 
         * 而这里的判断是为了连接上一个递归下来的根节点
         * 
          */
        
        
        // 当左子树不是完全二叉树时,就返回 -1 
        if (left < 0) {
           return -1;
       }
       
       int right=CheckTreeCount(root.right);
       
        // 当右子树不是完全二叉树时, 就返回 -1 
       if(right < 0) {
            return  -1;
        }

       
       // 当左子树的高度 < 右子树的高度
        // 就说明不是完全二叉树
        if (left < right) {
            return -1;
        } else {
            
            // 该节点是完全二叉树时,就返回当前高度
            return Math.max(left,right)+1;
        }

   }

在这里插入图片描述

具体实现,请小伙伴们观看下面动态理解哦 ❣️ ❣️ ❣️ ❣️

请添加图片描述

鱼式疯言

int left=CheckTreeCount(root.left);

        /**
         * 当此树不是完全二叉树的就返回 负数
         * 
         * 而这里的判断是为了连接上一个递归下来的根节点
         * 
          */
        
        
        // 当左子树不是完全二叉树时,就返回 -1 
        if (left < 0) {
           return -1;
       }
       
       int right=CheckTreeCount(root.right);
       
        // 当右子树不是完全二叉树时, 就返回 -1 
       if(right < 0) {
            return  -1;
        }

细节处理

这里有小伙伴就问了,我可以把

   if (left < 0) {
           return -1;
       }

if(right < 0) {
        return  -1;
    }

去掉吗?

答案是 不行

因为当我们一旦判断出 有一颗子树 的 左子树的高度 > 右子树的高度 时 , 就必须返回 -1 ,然后就必须回退到上一个 根节点

如果没有及时返回 -1 ,就有可能造成 max(-1,-1) 的情况,这种情况是 不可预料 的,所以我们呢需要 及时返回

总结

  1. 获取树中节点的个数: 我们通过都用了 子问题遍历 的获取节点的个数,但子问题要 注意的是需要加上自身的那个 节点数的 1

  2. 获取叶子节点的个数 : 获取叶子节点,我们主要是根据它自身的特点 (左右节点是否同时为 null ) ,成立时我们就返回 当前节点 .

  3. 获取第 K 层的节点的个数 : 获取 第K层的节点数 的思路在遍历的情况下,每走一层,k就减去1 , 当 k= 1 时就到达该层,返回 该层节点数 即可

  4. 获取二叉树的高度(最大深度):求树的高度,本质是抓住我们左子树和右子树的 较高 的那个高度,然后 加上 自身的高度1 即可

  5. 查找 节点的值等于的 value 的节点 :查找 val 是在遍历的情况下完成的,只需要在 边遍历边查找一旦找到就返回该节点即可

  6. 判断一棵树是否是完全二叉树 : 完全二叉树的判断是建立在获取二叉树高度的思路上进行变通的, 根据完全二叉树成立条件: 左子树 >= 右子树 ,这个特点来判断即可

如果觉得小编写的还不错的咱可支持 三连 下 (定有回访哦) , 不妥当的咱请评论区 指正

希望我的文章能给各位宝子们带来哪怕一点点的收获就是 小编创作 的最大 动力 💖 💖 💖

在这里插入图片描述

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

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

相关文章

[机器学习] 低代码机器学习工具PyCaret库使用指北

PyCaret是一个开源、低代码Python机器学习库&#xff0c;能够自动化机器学习工作流程。它是一个端到端的机器学习和模型管理工具&#xff0c;极大地加快了实验周期&#xff0c;提高了工作效率。PyCaret本质上是围绕几个机器学习库和框架&#xff08;如scikit-learn、XGBoost、L…

【Kubernetes】k8s集群的污点、容忍、驱逐 以及排障思路

污点和容忍以及驱逐 一、污点&#xff08;Taint&#xff09; 污点介绍 节点亲和性&#xff0c;是Pod的一种属性&#xff08;偏好或硬性要求&#xff09;&#xff0c;它使Pod被吸引到一类特定的节点。Taint 则相反&#xff0c;它使节点能够排斥一类特定的 Pod。 Taint 和 Tol…

【ai】livekit服务本地开发模式1:example app信令交互详细流程

文档要安装git lfs 下载当前最新版本1.6.1windows版本:启动dev模式 服务器启动 (.venv) PS D:\XTRANS\pythonProject\LIVEKIT> cd .

python实现——分类类型数据挖掘任务(图形识别分类任务)

分类类型数据挖掘任务 基于卷积神经网络&#xff08;CNN&#xff09;的岩石图像分类。有一岩石图片数据集&#xff0c;共300张岩石图片&#xff0c;图片尺寸224x224。岩石种类有砾岩&#xff08;Conglomerate&#xff09;、安山岩&#xff08;Andesite&#xff09;、花岗岩&am…

【笔记】Sturctured Streaming笔记总结(Python版)

目录 相关资料 一、概述 1.1 基本概念 1.2 两种处理模型 &#xff08;1&#xff09;微批处理 &#xff08;2&#xff09;持续处理 1.3 Structured Streaming和Spark SQL、Spark Streaming关系 二、编写Structured Streaming程序的基本步骤 三、输入源 3.1 File源 &a…

python-题库篇-为什么数组下标从0 开始而不是 1

为什么很多编程语言要把 0 作为第一个下标索引&#xff0c;而不是直观的 1 呢&#xff1f; 这个问题 Dijkstra 已经解答过了&#xff0c;没错&#xff0c;就是你知道的 Dijkstra&#xff0c;Dijkstra 最短路径算法&#xff0c;荷兰语全名是 Edsger Wybe Dijkstra&#xff0c;于…

linux查看磁盘类型命令

在Linux中&#xff0c;有多种方法可以查看磁盘是固态硬盘&#xff08;SSD&#xff09;还是机械硬盘&#xff08;HDD&#xff09;。以下是一些常用的方法&#xff1a; 查看/sys/block/目录 /sys/block/目录包含了系统中所有块设备的信息。你可以查看这个目录中的设备属性来判断…

保姆级教程:Redis 主从复制原理及集群搭建

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a;不…

LabVIEW在高校电力电子实验中的应用

概述&#xff1a;本文介绍了如何利用LabVIEW优化高校电力电子实验&#xff0c;通过图形化编程实现参数调节、实时数据监控与存储&#xff0c;并与Simulink联动&#xff0c;提高实验效率和数据处理能力。 需求背景高校实验室在进行电机拖动和电力电子实验时&#xff0c;通常使用…

文献解读-肿瘤测序-第五期|《局部晚期或转移性儿童及青少年分化型甲状腺癌的基因特征与临床特征及131I疗效的关系》

关键词&#xff1a;应用遗传流行病学&#xff1b;群体测序&#xff1b;肿瘤测序&#xff1b; 文献简介 标题&#xff08;英文&#xff09;&#xff1a;The relationship between genetic characteristics and clinical characteristics and the efficacy of 131I therapy in c…

opencv笔记(13)—— 停车场车位识别

一、所需数据介绍 car1.h5 是训练后保存的模型 class_directionary 是0&#xff0c;1的分类 二、图像数据预处理 对输入图片进行过滤&#xff1a; def select_rgb_white_yellow(self,image): #过滤掉背景lower np.uint8([120, 120, 120])upper np.uint8([255, 255, 255])#…

【YOLO系列】YOLOv10论文超详细解读(翻译 +学习笔记)

前言 研究AI的同学们面对的一个普遍痛点是&#xff0c;刚开始深入研究一项新技术&#xff0c;没等明白透彻&#xff0c;就又迎来了新的更新版本——就像我还在忙着逐行分析2月份发布的YOLOv9代码&#xff0c;5月底清华的大佬们就推出了全新的v10。。。 在繁忙之余&#xff0…

opencv进阶 ——(九)图像处理之人脸修复祛马赛克算法CodeFormer

算法简介 CodeFormer是一种基于AI技术深度学习的人脸复原模型&#xff0c;由南洋理工大学和商汤科技联合研究中心联合开发&#xff0c;它能够接收模糊或马赛克图像作为输入&#xff0c;并生成更清晰的原始图像。算法源码地址&#xff1a;https://github.com/sczhou/CodeFormer…

深度学习论文: DINOv2: Learning Robust Visual Features without Supervision

深度学习论文: DINOv2: Learning Robust Visual Features without Supervision DINOv2: Learning Robust Visual Features without Supervision PDF: https://arxiv.org/abs/2304.07193 PyTorch代码: https://github.com/shanglianlm0525/CvPytorch PyTorch代码: https://githu…

Transformer系列:注意力机制的优化,MQA和GQA原理简述

前言 多查询注意力(MQA)、分组查询注意力(GQA)是Transformer中多头注意力(MHA)的变种&#xff0c;它们大幅提高了解码器的推理效率&#xff0c;在LLaMA-2&#xff0c;ChatGLM2等大模型中有广泛使用&#xff0c;本篇介绍MQA、GQA的原理并分析其源码实现。 使用MQA&#xff0c;G…

Spring Boot前后端简单集成MinIo开发

Spring Boot前后端简单集成MinIo开发 源码地址重要配置和代码MinIO配置核心代码 最终效果 源码地址 minioStudy 重要配置和代码 MinIO配置 pom文件引入依赖 <!-- minio --> <dependency><groupId>io.minio</groupId><artifactId>minio</ar…

GaussDB的数种形态

GaussDB作为一种新兴的关系型数据库产品&#xff0c;似乎有点让人摸不着头脑。有朋友问我GaussDB单机版怎么样&#xff0c;有人说GaussDB是分布式数据库&#xff0c;还有人说它是云数据库&#xff0c;还有人会把GaussDB和华为的数据仓库GaussDB DWS混为一谈。确实&#xff0c;公…

AD域渗透链和工具推荐

xmind下载地址&#xff1a; 链接: https://pan.baidu.com/s/1_BsmqLvN6aBnan0AIk5iBA 提取码: j97j

笔记 | 软件工程02:软件工程概述

1 软件工程产生背景 1.1 历史发展 1960s的个体作坊式软件开发带来的问题 1.2 软件开发需要解决的问题 代码规模增长带来的影响&#xff1a; 1.3 软件开发面临的挑战 指挥信息系统中的软件&#xff1a;规模大、质量要求高 装备中嵌入式软件系统&#xff1a;规模大、质量要求…

【MySQL数据库】索引与事务

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【MySQL】探秘&#xff1a;数据库世界的瑞士军刀 目录 &#x1f5f3;️一.索引 &#x1f4ee;1.工作原理 &#x1f4ec;2.类型 &#x1f4ed;3.作用 &#x1f4ea;4.优缺点 &#x1f4eb;5.使用…