数据结构奇妙旅程之二叉平衡树

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱
ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客
本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转载还请通知˶⍤⃝˶
个人主页:xiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客
系列专栏:xiaoxie的JAVA系列专栏——CSDN博客●'ᴗ'σσணღ*
我的目标:"团团等我💪( ◡̀_◡́ ҂)" 

( ⸝⸝⸝›ᴥ‹⸝⸝⸝ )欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​+关注(互三必回)!

一.二叉平衡树

1.二叉平衡树的概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

若它的左子树不为空,则左子树上所有节点的值都小于根节点的值

若它的右子树不为空,则右子树上所有节点的值都大于根节点的值

它的左右子树也分别为二叉搜索树

从上述概念以及图中可以看出,二叉搜索树具有以下特性:

1. 二叉搜索树中最左侧的节点是树中最小的节点,最右侧节点一定是树中最大的节点

2. 采用中序遍历遍历二叉搜索树,可以得到一个有序的序列 

2.二叉搜索树的主要操作

1. 查询

2.插入

1.插入的为一颗空树

直接插入即可

2.. 如果树不是空树,按照查找逻辑确定插入位置,插入新结点

根据二叉搜索树的性质插入节点,"左小右大"

  1. 对于树中的任意节点 n,其左子树中的所有节点的值都小于 n 的值,其右子树中的所有节点的值都大于 n 的值。
  2. 在插入新节点时,需要按照二叉搜索树的性质找到合适的位置插入,保持树的有序性。
  3. 插入节点后,需要调整树的结构,保证树仍然是一个二叉搜索树。

3.删除

假设删除节点cur那么cur有以下几种情况

1.cur 的左孩子为空,右孩子不为空,

2.cur 的右孩子为空,左孩子不为空.

3.cur 的左右孩子均为空.

4.cur 的左右孩子均不为空.

接下来博主将会通过画图的形式来演示这四种情况该如何删除节点

1.cur 的左孩子为空,右孩子不为空

 2.cur 的右孩子为空,左孩子不为空.

3. cur 的左右孩子均为空.

4. cur 的左右孩子均不为空.

1.假设我们需要删除节点70,我们首先需要通过遍历二叉搜索树,找到70这个节点的对应位置.

2.我们发现70这个节点,左右孩子均不为空,这个时候就不可以通过简单的删除就可以了,我们需要用到替换法,即在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被 删除节点中,再来处理该结点的删除问题.

2.1这里解释一下为什么是在它的右子树中寻找中序下的第一个结点(关键码最小),当需要删除一个节点时,如果该节点有右子树,则可以在右子树中找到中序遍历下的第一个节点(即右子树中最小的节点)来替代当前节点。这是因为右子树中的所有节点都大于当前节点,而右子树中最小的节点又小于右子树中的所有其他节点,所以用右子树中的最小节点来替代当前节点可以保持二叉搜索树的性质不变。

3.找到"替罪羊"节点 t 后我们就需要把要删除的节点cur使他的值等于t .

4.最后删除节点t即可.

4.二叉搜索树基本操作的Java代码实现

public class BinarySearchTree {public static class TreeNode {public TreeNode left;public TreeNode right;public int val;public TreeNode(int val) {this.val = val;}}public TreeNode root;/*** 查询节点是否存在* @author xiaoxie* @date 2024/3/6 10:44* @param val* @return boolean*/public boolean search(int val) {if(root == null) {System.out.println();return false;}TreeNode cur = root;while (cur != null) {if(val < cur.val) {cur = cur.left;} else if (val > cur.val) {cur = cur.right;}else {System.out.println("找到了");return true;}}System.out.println("该节点"+val+"不存在");return false;}/*** 插入节点* @author xiaoxie* @date 2024/3/6 10:47* @param val*/public void insertTreeNode(int val) {TreeNode node = new TreeNode(val);if(root == null) {root = node;return;}TreeNode parent = null;TreeNode cur = root;while (cur != null) {if(node.val < cur.val) {parent = cur;cur = cur.left;} else if (node.val > cur.val) {parent = cur;cur = cur.right;}else {System.out.println("节点值 " + val + " 已经存在于树中,不进行插入操作");return;}}//cur = nullif(node.val < parent.val) {parent.left = node;}else {parent.right = node;}}/*** 删除节点* 可以使用替罪羊的方法来实现* @author xiaoxie* @date 2024/3/6 12:15* @param val* @return boolean*/public boolean remove(int val) {//首先先找到是哪一个节点if(root == null) {return false;}TreeNode parent = null;TreeNode cur = root;while (cur != null) {if(cur.val > val) {parent = cur;cur = cur.left;} else if (cur.val < val) {parent = cur;cur = cur.right;}else {break;}}//cur == null 说明要删除的节点不在二叉搜索树上if(cur == null) {return false;}// cur有多种情况//1.cur 没有左右孩子//2.cur 只有左孩子//3.cur 只有右孩子//4.cur 有左右孩子 -- 需要使用替罪羊的方法来删除if(cur.right != null && cur.left != null) {TreeNode t = cur.right;TreeNode tp = cur;while (t.left != null) {tp = t;t = t.left;}cur.val = t.val;//使要删除的节点的值等于替罪羊节点//删除替罪羊节点if(tp.left == t) {tp.left = t.right;}else {//出现tp.right = t 的情况,t节点一开始就是叶子节点tp.right = t.right;}}else {//cur 只有右孩子if(cur.left == null && cur.right != null){if(parent == null) {root = cur.right;}else {if(parent.val < cur.val) {parent.right = cur.right;}else {parent.left = cur.right;}}}//cur 只有左孩子else if (cur.left != null && cur.right == null) {if(parent == null) {root = cur.left;}else {if(parent.val < cur.val) {parent.right = cur.left;}else {parent.left = cur.left;}}}//cur 没有左右孩子else  {if(parent == null) {root = null;}else {if(parent.val < cur.val) {parent.right = null;}else {parent.left = null;}}}}return true;}

 5.性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。 对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度 的函数,即结点越深,则比较次数越多。 但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:

1.最优情况下,二叉搜索树为完全二叉树

其平均比较次数为:log N;

2.最差情况下,二叉搜索树退化为单支树

 其平均比较次数为: 2 / N

问题:如果退化成单支树,二叉搜索树的性能就失去了。那能否进行改进,不论按照什么次序插入关键码,都可以 是二叉搜索树的性能最佳?

那就需要用到AVL树了通过旋转来使二叉搜索树变成完全二叉树的形式,这里博主就不过多的赘述了,如果感兴趣,可以为博主点上一个关注,在下一篇文章中,博主将详细解读AVL树

感谢你的阅读!

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

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

相关文章

图神经网络实战(4)——基于Node2Vec改进嵌入质量

图神经网络实战&#xff08;4&#xff09;——基于Node2Vec改进嵌入质量 0. 前言1. Node2Vec 架构1.2 定义邻居1.2 在随机游走中引入偏向性1.3 实现有偏随机游走 2. 实现 Node2Vec小结系列链接 0. 前言 Node2Vec 是一种基于 DeepWalk 的架构&#xff0c;DeepWalk 主要由随机游…

深入理解nginx upstream共享内存机制

目录 1. 概述2. 开启upstream共享内存机制3. 源码分析3.1 配置指令分析3.2 共享内存区的初始化1. 概述 我们知道,nginx的配置是由主进程来加载到内存的,然后fork出各个worker进程,而worker进程自然继承了主进程的内存状态,所以worker进程自然有了加载好的配置信息。然而,每…

北约 / 多个国家地区的 数据链 汇总

战术数据链 编号用途说明Link-1地地北约用于NADGE(北约地面防空系统)的雷达情报数据传输Link-2地地其功能类似于Link-1&#xff0c;用于北约陆基雷达站间的数据传输&#xff0c;现已停止发展Link-3地地类似于Link-14的低速电报数据链&#xff0c;用于某些防空预警单元Link-4空…

python实现--分块查找

python实现–顺序查找 python实现–折半查找 python实现–分块查找 python实现B/B树 分块查找&#xff08;Block Search&#xff09;&#xff0c;也称为索引顺序查找&#xff0c;是一种结合顺序查找和索引查找思想的查找算法。它适用于线性表中数据量较大&#xff0c;但是分布不…

qt 格式化打印 日志 QMessagePattern 格式词法语法及设置

一、qt源码格式化日志 关键内部类 QMessagePattern qt为 格式化打印日志 提供了一个简易的 pattern(模式/格式) 词法解析的简易的内部类QMessagePattern,作用是获取和解析自定义的日志格式信息。 该类在qt的专门精心日志操作的源码文件Src\qtbase\src\corelib\global\qloggi…

[LeetCode][226]翻转二叉树

题目 226. 翻转二叉树 给你一棵二叉树的根节点 root&#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1] 示例 2&#xff1a; 输入&#xff1a;root [2,1,3] 输出&#x…

深度学习500问——Chapter02:机器学习基础(5)

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 2.14 贝叶斯分类器 2.14.1 图解极大似然估计 极大似然估计的原理&#xff0c;用一张图片来说明&#xff0c;如下图所示&#xff1a; 例&#xff1a;有两个外形完全相同的箱子&#xff0c;1号箱…

重学SpringBoot3-内容协商机制

重学SpringBoot3-内容协商机制 ContentNegotiationConfigurer接口配置内容协商URL参数Accept头使用Url扩展名 自定义内容协商格式步骤1: 注册自定义媒体类型步骤2: 实现HttpMessageConverter接口步骤3: 使用自定义HttpMessageConverter 注意点 在 Spring Boot 3 中&#xff0c;…

linux系统Docker容器Dockerfile示例

Dockerfile示例 可以使用systemctl命令的镜像Dockerfile 基于centos7创建mysql镜像Dockerfilemysql.sh 可以使用systemctl命令的镜像 Dockerfile vim DockerfileFROM centos:7 ENV container dockerRUN yum -y swap -- remove fakesystemd -- install systemd systemd-libs R…

SQL中如何添加数据:基础指南

在数据库管理系统中&#xff0c;添加数据是一项常见的任务。无论是向现有表中添加新行&#xff0c;还是创建新表并插入数据&#xff0c;都需要使用SQL&#xff08;Structured Query Language&#xff09;语句来执行。本文将介绍SQL中如何添加数据的基本方法&#xff0c;以及一些…

vue学习笔记21-组件传递数据_Props

组件与组件之间不是完全独立的&#xff0c;而是有交集的&#xff0c;那就是组件与组件之间是可以传递数据的 传递数据的解决方案就是props 父级&#xff1a; 在父级中引入子集 <template><h3>Parent</h3><Child/> </template><script> i…

PyCaret(Python自动化机器学习)自定义交互式解释性模型

要点 PyCaret代码实现数学定义分类、聚类、异常检测和自然语言处理模型PyCaret模型创建模型和数据分析&#xff1a;身体质量指数回归模型探索性数据分析&#xff0c;植物物种分类模型预测&#xff0c;合成数据聚类模型探索性数据分析&#xff0c;批发商客户异常检测模型探索性…

GFP-GAN环境搭建推理测试

引子 近期&#xff0c;文生图&#xff0c;wav2lip很火&#xff0c;文生图&#xff0c;见识的太多&#xff0c;不多说了。wav2lip其通过语音驱动唇部动作并对视频质量进行修复&#xff0c;里面一般涉及到三个步骤&#xff0c;文本到语音转化&#xff0c;语音驱动唇部动作&#…

YOLOv9/YOLOv8算法改进【NO.103】引入YOLOv9提出模块RepNCSPELAN模块,亲测有效

前 言 YOLO算法改进系列出到这,很多朋友问改进如何选择是最佳的,下面我就根据个人多年的写作发文章以及指导发文章的经验来看,按照优先顺序进行排序讲解YOLO算法改进方法的顺序选择。具体有需求的同学可以私信我沟通: 首推,是将两种最新推出算法的模块进行融合形成…

【C++初阶】第五站:C/C++内存管理 (匹配使用,干货到位)

前言&#xff1a; 本文知识点&#xff1a; 1. C/C内存分布2. C语言中动态内存管理方式3. C中动态内存管理4. operator new与operator delete函数 5. new和delete的实现原理 &#xff08;干货在此&#xff09; 6. 定位new表达式(placement-new)7. 常见面试题 目录 C/C内…

Linux操作系统内核参数调优-2

1. 请解释Linux内核参数调优的目的和重要性。 Linux内核参数调优的目的主要是提高系统性能、稳定性和安全性。它的重要性体现在以下几个方面&#xff1a; 提升系统性能&#xff1a;通过调整内核参数&#xff0c;可以使系统更高效地利用硬件资源&#xff0c;例如CPU、内存和I/…

Java反射、枚举类和lambda表达式

前言&#xff1a; 本章我们就来了解Java中的反射和枚举类。枚举类和反射其实有些关系&#xff0c;接下来我们就来学习他们的使用。 反射&#xff1a; 反射的作用&#xff1a; 反射&#xff1a;反射允许对成员变量&#xff0c;成员方法和构造方法的信息进行编程访问。 Java中有…

CVE-2021-31440:eBPF verifier __reg_combine_64_into_32 边界更新错误

文章目录 前言漏洞分析构造 vuln reg 漏洞利用漏洞修复参考 前言 影响版本&#xff1a;Linux 5.7 ~ 5.11.20 8.8 编译选项&#xff1a;CONFIG_BPF_SYSCALL&#xff0c;config 所有带 BPF 字样的编译选项。General setup —> Choose SLAB allocator (SLUB (Unqueued Allocat…

从0到1手把手实现RPC|01 RpcProvider本地实现

RPC的简化版原理如下图&#xff08;核心是代理机制&#xff09;。 1.本地代理存根: Stub2.本地序列化反序列化3.网络通信4.远程序列化反序列化5.远程服务存根: Skeleton6.调用实际业务服务7.原路返回服务结果8.返回给本地调用方 注意处理异常。 RpcProvider的本地实现 1、工…

xss.haozi.me靶机 通关

0x00 没有任何过滤可以直接注入<img srcx οnerrοralert(1)> 0x01 使用了testarea标签将我们的输入内容以普通的字符串进行展示 但是我们可以将标签进行闭合 </textarea><img srcx οnerrοralert(1)> 0x02 我们依然可以先闭合之后添加属性a" οncl…