【用Java学习数据结构系列】震惊,二叉树原来是要这么学习的(二)

看到这句话的时候证明:此刻你我都在努力

加油陌生人

个人主页:Gu Gu Study
专栏:用Java学习数据结构系列
喜欢的一句话: 常常会回顾努力的自己,所以要为自己的努力留下足迹

喜欢的话可以点个赞谢谢了。
作者:小闭

前言

今天这篇文章是二叉树的第二篇文章,上一篇文章已经简单讲述了二叉树的各种遍历方法了,那么接下来就需要进阶一下,开始用二叉树的知识解决更多问题。如有哪里出现错误也欢迎指出唔。

那么我们先来开始我们今天的第一道小菜。

根据中序遍历和后序遍历写出前序遍历

设一课二叉树的 中序遍历序列:badce,后序遍历序列:bdeca

那么我们如何下手呢?首先我们先根据我们的知识来得出一些关键点。

  1. 后序遍历的最后一个节点就是根节点
  2. 那么我们就可以根据根节点在中序遍历中得出树的左右两边的节点
  3. 根据得出的信息开始逐渐还原树的样子,然后就可以根据树的样子得出前序遍历的顺序。

根据信息得出树,然后核对一下已知的连个遍历序列是否正确,如果正确那么我们就可以写出前序遍历的顺序了。

获取树的节点个数

我们既然要获取节点个数那么肯定需要我们取遍历这棵树了,除非你在这棵树创建加了个size变量来计数。

那么如果我们的树没有定义一个计数变量我们就必须得遍历这棵树了。

int size(BTNode root) {if (root == null) {return 0;}return size(root.left) + size(root.right) + 1;}

我采用的是递归的方法,假设把每个节点都当作根节点(即假设该节点上方的节点是不存在的),那么他这棵树的节点树就等于左树的节点数加上右树的节点树加上1(这个1就是该节点本身)。代码的实现就如上面所示。


获取叶子节点的个数

获取节点数是比较简单的那么我们现在来进阶一下,我们来求一下一颗树的叶子节点个数,那么这样我们又该怎么操作呢?

首先我们需要先知道什么是叶子节点,叶子节点就是最后一层树的节点即:该节点既没有左孩子也没有右孩子。

那么根据这个关键点就可以写出代码了,当然我们还是需要遍历这棵树的。

int getLeafNodeCount(BTNode root) {if (root == null) {return 0;} else if (root.left == null && root.right == null) {return 1;}return getLeafNodeCount(root.left) + getLeafNodeCount(root.right);}

那么还是整棵树的叶子节点等于左树的叶子节点加上右树的叶子节点。


获取第K层节点的个数

那么我们要知道第k层的节点就需要想如何定位到第k层。

首先我们可以想着用一个整型变量来作为标记,当该变量为某个数时就表示该层就是第k层。既然要知道节点的个数那么遍历肯定是必不可少的。那么我们就用形参作为标记,当k==1时我们就返回1即可。

int getKLevelNodeCount(BTNode root, int k) {if (root == null||k<1) {return 0;}if (k == 1) {return 1;}return getKLevelNodeCount(root.left, k - 1)+getKLevelNodeCount(root.right, k - 1);}


求二叉树的高度

求数的高度我们需要先 捋清思路:

首先我们要知道树的高度也可以说是树有几层,那么我们只需要挑出一条最高的一条路的高度即可

那么我们就一直遍历,每遍历多一层就+1,直到节点为null,然后我们就对比是左树的高还是右树的高度高,挑出最高的那个进行返回即可。

int getHeight(BTNode root) {if (root == null) {return 0;}int n1 = getHeight(root.left) + 1;int n2 = getHeight(root.right) + 1;return n1 > n2 ? n1 : n2;}


二叉树层序遍历

那么首先我们要知道什么是层序遍历,层序遍历就比上一篇的三种遍历稍微简单,而且比较好理解

层序遍历就是将一颗树从上到下,从左到右开始遍历,一层一层遍历,每一层都是从左边遍历到右边

那么举一个例子吧:

想这么一颗二叉树它层序遍历的结果就是1 2 4 3 5 6,所以说是从上到下,从左到右开始遍历,一层一层遍历,每一层都是从左边遍历到右边。

那么代码如何实现呢?这里我们就需要到一个队列来实现了,我们在循环中将每个树的节点的左右孩子依次add到队列中,然后每次循环都出一个队列数据。那么根据思路就可以写出下面的代码了:

//层序遍历
void levelOrder(BTNode root) {if (root == null) {return;}Queue<BTNode> queue = new LinkedList();queue.add(root);while (!queue.isEmpty()) {BTNode node = queue.poll();System.out.print(node.value + " ");if (node.left != null) {queue.add(node.left);if (node.right != null) {queue.add(node.right);}}}}


判断一棵树是否为完全二叉树

前面已经说过什么是完全二叉树了。现在温习一下吧。

完全二叉树:如果一个二叉树的所有层都被完全填满,除了最后一层,并且最后一层的节点尽可能地集中在左侧,这样的二叉树称为完全二叉树。

也就是说在如果最后一层在左边没有填满,右边就突然有一个节点,那么他就不是完全二叉树。如下就不是一棵完全二叉树:

那么代码又要如实现判断一棵树是否是完全二叉树呢。

首先我们想到其实完全二叉树也需要从上到下,从左到右进行观察,看有没有同一层的节点是相隔一个节点或以上的。那么我们就可以从层序遍历的代码里进寻求灵感进行改动。

// 判断一棵树是不是完全二叉树
boolean isCompleteTree(BTNode root) {if (root == null) {return true;}Queue<BTNode> queue = new LinkedList();queue.add(root);while (!queue.isEmpty()) {BTNode node = queue.poll();if(node==null) {break;}queue.add(node.left);queue.add(node.right);}while (!queue.isEmpty()){BTNode node=queue.poll();if(node!=null){return false;}}return true;
}

我们在循环体中不在判断node的左右孩子是否为空,而是无条件add到队列,然后在node为空的时候就break,如果这时这棵树是完全二叉树那么这时的队列里面的数据就会是n个null(注意null也是队列里的数据,也可以add进队列,这时队列不是空的),我们只需判断剩下的队列里面的成员是否全为null,如果是说明它是一颗完全二叉树否则就不是。


判断两颗二叉树是否相等

正如标题所写如何判断两棵二叉树是否相等,实现也是比较简单的,在判断节点是否为null的问题后,在判断值是否相等即可,然后进行递归

/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
class Solution {public boolean isSameTree(TreeNode p, TreeNode q) {if(p==null&&q!=null||q==null&&p!=null){return false;}if(p==null&&q==null){return true;}if(p.val!=q.val){return false;}return isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);}
}

是不是一棵子树

给定你两条树的根节点,判断其中一颗是不是另一颗的子树,这个代码又该如何写呢?

写这道题的时候,看见了一位大佬的方法是比较厉害的,所以打算就用他的优质方法给你们进行讲解。

首先我们要判断是不是子树,那么按正常情况来说,在两棵树都不为null的情况下,他们如果存在子树关系,那么那颗比较大的树就会从某个节点开始和子树的节点完全相同,直到子树为null

然后看到相同两个字我们是不是又可以用到上面的求两颗树是否相同的方法。如果不是从这个节点开始相同,那么就往左右两个孩子节点判断。

class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) { this.val = val; }TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}}class Solution {public boolean isSubtree(TreeNode root, TreeNode subRoot) {if(subRoot==null){return true;}if(root==null){return false;}return isSubtree(root.left,subRoot)||isSubtree(root.right,subRoot)||isSame(root,subRoot);}public boolean isSame(TreeNode root, TreeNode subRoot) {if(root==null&&subRoot==null){return true;}if(root==null||subRoot==null){return false;}if(root.val!=subRoot.val){return false;}return isSame(root.left,subRoot.left)&&isSame(root.right,subRoot.right);}}

思路:先判断不正常情况下,即两棵树是否为null的情况。然后开始递归大的树的节点即可。

这段代码中其中最精妙的地方就是这个语句。

return isSubtree(root.left,subRoot)||isSubtree(root.right,subRoot)||isSame(root,subRoot);

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Sql查询优化--索引设计与sql优化(包含慢查询定位+explain解释计划+左匹配原则+索引失效)

本文介绍了数据库查询的索引优化方法&#xff0c;依次介绍了慢查询语句定位方法、索引设计与sql语句优化方法&#xff0c;并介绍了左匹配原则和索引失效的场景&#xff0c;最后介绍了explain执行计划要怎么看以调整检验索引设计是否生效和效率情况&#xff0c;创新介绍了如何以…

Visual Studio Code 自定义字体大小

常用编程软件自定义字体大全首页 文章目录 前言具体操作1. 打开首选项设置对话框2. 在Font Family里面输入字体 前言 Visual Studio Code 自定义字体大小&#xff0c;统一设置为 Cascadia Code SemiBold &#xff0c;大小为 14 具体操作 【文件】>【首选项】>【设置】&…

18037 20秒后的时间

### 思路 1. 读取输入的时间&#xff0c;格式为小时:分钟:秒。 2. 将时间转换为秒数。 3. 增加20秒。 4. 将增加后的秒数转换回小时:分钟:秒格式。 5. 输出结果&#xff0c;确保小时、分钟和秒均占两个数字位&#xff0c;不足位用0补足。 ### 伪代码 1. 读取输入的时间字符串。…

day35-测试之性能测试JMeter的测试报告、并发数计算和性能监控

目录 一、JMeter的测试报告 1.1.聚合报告 1.2.html报告 二、JMeter的并发数计算 2.1.性能测试时的TPS&#xff0c;大都是根据用户真实的业务数据&#xff08;运营数据&#xff09;来计算的 2.2.运营数据 2.3.普通计算方法 2.4.二八原则计算方法 2.5.计算稳定性测试并发量 2.6…

vscode中如何设置不显示隐藏文件

在vscode中&#xff0c;有时候&#xff0c;会显示一些隐藏文件&#xff0c;如何设置让其不显示呢&#xff1f; 解决办法 例如&#xff1a;我这里有一个.vscode隐藏文件夹&#xff0c;是vscode默认生成的一个配置目录&#xff0c;我想要它不在资源管理器中进行显示。 操作步骤&a…

Java 入门指南:Java 并发编程 —— Condition 灵活管理线程间的同步

Condition Condition 是 Java 并发编程中的一种高级同步工具&#xff0c;它可以协助线程之间进行等待和通信。提供了一种比传统的 wait() 和 notify() 更加灵活的方式来管理线程间的同步。Condition 接口通常与 Lock 接口一起使用&#xff0c;允许更细粒度的控制线程的等待和唤…

Python 从入门到实战4(序列的操作)

我们的目标是&#xff1a;通过这一套资料学习下来&#xff0c;通过熟练掌握python基础&#xff0c;然后结合经典实例、实践相结合&#xff0c;使我们完全掌握python&#xff0c;并做到独立完成项目开发的能力。 上篇文章我们通过举例学习了python 中列表的简单操作&#xff0c;…

Android CCodec Codec2 (六)C2InterfaceHelper

通过前面几篇文章的学习&#xff0c;我们知道了Codec2参数结构&#xff0c;以及如何定义一个Codec2参数。接下来的几篇文章我们将简单了解上层是如何请求组件支持的参数、如何配置参数&#xff0c;以及参数是如何反射给上层的。本篇文章我们将了解接口参数实例化。 1、C2Interf…

SprinBoot+Vue社团管理系统的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质…

【最全深度学习介绍】基本概念、类型、应用、优缺点、与机器学习区别是什么?

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发…

excel规划求解结合vba宏笔记

目录 概念与配置 规划求解定义 excel设置规划求解 宏的基本操作 excel批量进行规划求解案例 加载规划求解模块 宏的设置 宏录制vba 其他案例 概念与配置 规划求解定义 运用“规划求解”定义并求解问题 - Microsoft 支持 excel设置规划求解 EXCEL规划求解的简明教程…

HarmonyOS鸿蒙开发:在线短视频流畅切换最佳实践

简介 为了帮助开发者解决在应用中在线短视频快速切换时容易出现快速切换播放时延过长的问题&#xff0c;将提供对应场景的解决方案。 该解决方案使用&#xff1a; 视频播放框架AVPlayer和滑块视图容器Swiper进行短视频滑动轮播切换。绘制组件XComponent的Surface类型动态渲染…

midwayjs 框架使用 rabbitmq 消息延迟

插件rabbitmq_delayed_message_exchange是RabbitMQ官方提供的一种用于实现延迟消息的解决方案。该插件将交换机类型扩展至x-delayed-message&#xff0c;这种类型的交换机能够将消息暂时挂起&#xff0c;直到设定的延迟时间到达&#xff0c;才将消息投递到绑定的队列中。这一特…

js做一个带模糊搜索、自动补全的select组件auto-input-select

效果图&#xff1a; 思路 原本是想弄一个输入框input&#xff0c;挡在原生select的前面&#xff0c;结果发现&#xff0c;原生select无论怎么弄&#xff0c;都无法js手动控制展开下拉选&#xff0c;必须点击select&#xff0c;这就很尴尬 然后就只能弄一个输入框input&#x…

python-变量声明、数据类型、标识符

一.变量 1.什么是变量 为什么需要变量呢&#xff1f; 一个程序就是一个世界&#xff0c;不论使用哪种高级程序语言编写代码&#xff0c;变量都是其程序的基本组成单位。如下图所示的sum和sub都是变量。 变量的定义&#xff1a; 变量相当于内存中一个数据存储空间的表示&#…

【Unity小工具】Image组件宽度、高度自适应

Unity开发中&#xff0c;用同一个Image进行动态加载不同尺寸的图片&#xff0c;在显示上会有形变此工具可以进行Image的宽度、高度自适应 实现原理 获取Image原始尺寸&#xff08;sizeDelta&#xff09;获取图片原始尺寸&#xff08;spriteSizeDelta&#xff09;公式&#xff…

Git 忽略已经提交的文件

对于未提交过的文件直接用ignore文件即可,不再赘述 对于已经提交过的文件,但是实际上不需要的,可以用git rm --cached命令 比如下图这个 .vsconfig被我误提交了或者忘了在ignore里添加了 但是我实际上不想要这个文件,那么在项目根目录打开git bash ,输入 git rm --cached .vsc…

【Hot100】LeetCode—34. 在排序数组中查找元素的第一个和最后一个位置

目录 1- 思路二分 - 左侧二分 右侧二分 2- 实现⭐34. 在排序数组中查找元素的第一个和最后一个位置——题解思路 3- ACM 实现 原题链接&#xff1a;34. 在排序数组中查找元素的第一个和最后一个位置 1- 思路 二分 - 左侧二分 右侧二分 右区间二分 ——> 找首次出现的位置…

unreal engine5.4.3动画重定向

UE5系列文章目录 文章目录 UE5系列文章目录前言 前言 ue5.4和ue3动画重定向之间存在差异&#xff0c;跟ue5.2差别更大一点&#xff0c;总之ue5.4越来越简化动画重定向&#xff0c;不想之前还需要制作RTG文件 这是ue5.3.2的制作动画重定向的界面 这是ue5.4.2的制作动画重定向…

编译FFmpeg动态库

编译FFmpeg动态库 环境 macOS High SierraFFmpeg 4.3android-ndk-r21b 编译so库 下载FFmpeg4.3源代码&#xff0c;进入源码目录创建build_android.sh脚本&#xff0c;ffmpeg从4.0起新增了target-osandroid&#xff0c;所以不用再修改configure文件。 注意&#xff1a; ndk…