7.4.1_2B树的插入删除

B树插入:

假如是m阶B树,插入关键字时都要满足每个节点上的关键字个数最少为m/2向上取整-1关键字,最多有m-1个关键字,且每次插入的新元素一定是放在最底层的终端节点(因为如果不是放在终端节点,会导致该节点上可能有叶子节点,则就不满足B树的叶子节点一定在最下层的特性了)

如下例子是5阶B树即m=5,则每个节点的关键字个数满足2<=n<=4

先插入25关键字,然后插入38,38>25,则插入在25的后边,插入49关键字,49>38,49放在38的后边,插入60,60>49,60放在49的后面,以上插入元素节点上的关键字个数都满足>=2且<=4

插入关键字80,80>60,则80放在60的后边,此时该节点上关键字的个数为5>4,则开始节点分裂调整。调整时使用m/2向上取整即5/2向上取整为3,从第3个位置将关键字分为2部分,左部分关键字放在原节点中,右部分关键字放到新节点中,中间位置m/2向上取整位置即第3个位置的节点插入原节点的父节点,因为原节点没有父节点,所以要向上新建个节点作为父节点。即从第3个位置即从49开始分成2部分,49左部分的25、38还在原节点,49右部分的60、80放到新节点,49关键字放到新节点且作为原节点的父亲,即49变成(25、38)节点和(60、80)节点父亲。

插入关键字90,从根节点49开始,90一定插入在最底层的终端节点,49旁边已经没有其他关键字了且90>49,90则要插入49右边的指针指向的节点上,然后开始比较关键字大小来确定具体放的位置,90>60,放在60后边,90>80,则90放在80后边,继续插入关键字99

 

插入关键字88,从根节点49开始,88一定插入在最底层的终端节点,49旁边已经没有其他关键字了且88>49,88则要插入49右边的指针指向的节点上,然后开始比较关键字大小来确定具体放的位置,88>60,放在60后边,88>80,则88放在80后边,88<90,则88放在90前边,即88放在80后边,此时该节点上关键字的个数为5>4,则开始节点分裂调整。调整时使用m/2向上取整即5/2向上取整为3,即从第3个位置即从88开始分成2部分,88左部分的60、80还在原节点,88右部分的90、99放到新节点,88关键字向上提到原节点的父节点中,即把88放到49关键字所在节点中,具体88放在指向该节点的分叉所属的指针黑点右边的位置,即88放在49后边的位置,且让88关键字右边的指针指向新节点(90,99),留在原节点的(60,80)指向啥的不变,还是让以前的指针指向该节点。这样能保证B树特性,即该关键字左边指针指向的节点上的关键字都<该关键字,该关键字右边指针指向节点上的关键字都>该关键字

 

插入关键字70,根节点49开始,77一定插入在最底层的终端节点,77>49且77<88,则77要插入49右边的指针88关键字左边指针指向的节点上,即60、70关键字所在的节点,然后开始比较关键字大小来确定具体放的位置,70>60,放在60后边,77<80,则77放在80前边,即77放在60后边80前边,此时该节点上关键字的个数为5>4,则开始节点分裂调整。调整时使用m/2向上取整即5/2向上取整为3,即从第3个位置即从80开始分成2部分,80左部分的(60,70)还在原节点,80右部分的(83,87)放到新节点,80关键字向上提到父节点中,即把80放到49关键字所在节点中,具体80放在指向该节点的分叉所属的指针黑点右边的位置,即80放在49后边的位置,且让80关键字右边的指针指向新节点(83,87),留在原节点的(60,70)指针指向啥的不变,还是让以前的指针指向该节点。即当一个节点要分裂,要把该节点上的中间的关键字放到这个节点的父节点中,具体放的位置为指向该节点的分叉所属的指针黑点右边的位置,这样才能保证B树的特性。继续插入关键字93、94。

 

插入关键字99,如下所示插入到94后边的位置,此时99所在节点的关键字个数为5>4,开始调整,节点要分裂。调整时使用m/2向上取整即5/2向上取整为3,即从第3个位置即从93开始分成2部分,93左部分的(90,92)还在原节点,93右部分的(94,99)放到新节点,93关键字向上提到父节点中,即把93放到49关键字所在节点中,具体放的位置为指向该节点的分叉所属的指针黑点右边的位置,这样才能保证B树的特性。即把93放在88旁边的黑点的右边的位置即88的后边,再让93关键字右边的指针黑点指向(94,99),留在原节点(90,92)的指针指向不变,还是让原指针指向(90,92)。继续插入关键字73,74

 

插入关键字75,如下所示插入到74后边的位置,此时74所在节点的关键字个数为5>4,开始节点分裂调整。调整时使用m/2向上取整即5/2向上取整为3,即从第3个位置即从73开始分成2部分,73左部分的(60,70)还在原节点,73右部分的(74,75)放到新节点,73关键字向上提到父节点中,即把73放到49关键字所在节点中,具体放的位置为指向该节点的分叉所属的指针黑点右边的位置,这样才能保证B树的特性。即把73放在原来指向该节点的黑点右边即88前边黑点后边位置,再让73关键字右边的指针黑点指向新节点(74,75),留在原节点(60,70)黑点的指针指向啥的不变,此时父节点73所在位置关键字个数为5>4还要开始节点分裂调整。调整时使用m/2向上取整即5/2向上取整为3,即从第3个位置即从80开始分成2部分,80左部分的(49,73)还在原节点,80右部分的(88,93)放到新节点,80关键字向上提到父节点中,没有父节点就新建一个节点作为父节点再把80放进去。即把80放到新节点中,即新的父节点中只有80一个关键字,即此时根节点就只有一个关键字,但是也满足5阶B树的特性(详情可去看B树特性)。让80关键字右边的指针黑点指向新节点(88,93),留在原节点(49,73)黑点的指针指向啥的不变。

B树删除:

所有非终端节点的关键字的删除都可转为终端节点的关键字删除,所以重点在于终端节点关键字的删除。

删除关键字60(删除终端节点关键字):因为是终端节点关键字,则直接删除就行,删除后确定是否当前节点的关键字个数是否满足节点关键字下限,为5阶B树,则下限为2,此时删除60后,当前节点还有3个关键字,3>=2则依然满足下限

 

 删除关键字80(删除关键字在非终端节点):

删除关键字为非终端节点关键字,则可用该节点的直接前驱或直接后继来代替被删除的关键字。

直接前驱:当前关键字左侧指针所指子树中最右下元素

如图2中80直接前驱为,80的左侧指针指向的是49关键字所在的节点,即该子树中最右下(最下一层的最右边)元素为77,即用77把80替换了,此时对非终端节点关键字删除的操作转成了对终端节点关键字删除的操作,因为原77所在节点上的77后边没有其他关键字了,所以不用再移动关键字了???

用直接后继代替删除的元素,假如删除左图3中的77关键字,即删除非终端节点上的关键字:

直接后继:当前关键字右侧指针所指子树中最左下元素

如图4中77的直接后继为,77右侧指针所指子树即为(88,93)所在节点,即该子树中的最左下(最下一层的最左边)元素为82,即用82把77替换了,此时对非终端节点关键字删除的操作转成了对终端节点关键字删除的操作,直接把82所在节点的关键字往前移动即可

删除38关键字(删除终端节点关键字,删除后当前节点关键字个数<下限,借右兄弟):

当前节点缺关键字时,借当前节点的右兄弟节点的关键字。看缺关键字的节点的右兄弟节点的关键字个数是不是 很宽裕,宽裕的话用当前节点的后继(即指向当前节点的父节点的黑点后的第一个关键字)、后继的后继(即上边后继关键字右边的第一个黑点指向的节点的第一个关键字)来填补空缺,把当前节点的后继即指向当前节点的父节点的黑点后的第一个关键字填补到当前节点的所有关键字后边(因为填补的关键字是后继肯定比该待填补节点上的关键字值都大),再把后继的后继即(即上边后继关键字右边的第一个黑点指向的节点的从左到右的第一个关键字)代替上述父节点被用来填补关键字的位置,再把后继的后继(即上边后继关键字右边的第一个黑点指向的节点的从左到右的第一个关键字)的所在节点上的关键字向前移动(因为少了一个关键字)

如下图删除关键字38了之后,38原本所在的节点的关键字个数==1<下限2,则要开始补充当前节点的关键字个数。删除关键字38了之后,38原本节点的关键字只剩25,25的右兄弟节点(70,71,72)关键字个数宽裕,可以从右兄弟借。找25的后继关键字即要从指向该节点的父节点查找即25的直接后继是25的父节点的第一个关键字49,49的后继要从49后边的指针指向的节点找,即49后边的指针指向的节点的第一个关键字70即为49的后继,让49的后继70代替49的位置,49补充到缺关键字的节点即25关键字的后边,然后再把原70所在节点的关键字依次往前移动。(这样补充是为了满足节点内部的关键字有序特性,不能直接把70放到25后边,那70>49了还在49的左边就不对了)

 

删除90关键字(删除终端节点关键字,删除后当前节点关键字个数<下限,借左兄弟):

当前节点缺关键字时,借当前节点的左兄弟节点的关键字。看缺关键字的节点的左兄弟节点的关键字个数是不是很宽裕,宽裕的话用当前节点的前驱(即指向当前节点的父节点的黑点前的第一个关键字)、前驱的前驱(即上边的前驱关键字的左边第一个黑点指向的子节点上的最后一个关键字)来填补空缺,把当前节点的前驱(即指向当前节点的父节点的黑点前的第一个关键字)填补到缺关键字的节点的最前边,再把缺关键字的节点上的关键字都后移,后继的后继(即上边的前驱关键字的左边第一个黑点指向的子节点上的最后一个关键字)代替上述父节点的刚填补完空缺的关键字位置

如下图删除关键字90了之后,90原本所在的节点的关键字个数==1<下限2,则要开始补充当前节点的关键字个数。删除关键字90了之后,90原本节点的关键字只剩92,且此时90所在节点的右兄弟节点(94,99)关键字个数也不宽裕(借它一个,它又不满足下限了),而当前节点的左兄弟节点(83,86,87)关键字个数宽裕,所以可以朝左兄弟借。92的前驱关键字要从指向该节点的父节点的黑点前的第一个关键字查找,即92的直接前驱是88,88的前驱要从88关键字前边的第一个黑点指针指向的子节点的最右的关键字找,即88前边的指针指向的子节点的最后一个关键字87即为88的前驱,让88填补到缺关键字92所在的节点中,然后92关键字向后移动,再让87补充到88的位置。

 

删除节点49(删除终端节点关键字,删除后当前节点关键字个数<下限,合体):

当兄弟不够借时,把当前节点和兄弟节点以及当前节点和兄弟节点中间的那个父节点的关键字合并成一个节点,因为从父节点借了一个关键字,导致父节点的关键字个数-1,如果父节点是根节点且-1之后关键字个数为0,则删除根节点,如果不是根节点且导致父节点的关键字个数<下限,则需要调整父节点的关键字个数,继续把父节点+父节点的兄弟节点+2个节点中间的爷节点的一个关键字合并成一个节点,然后再判断借了一个关键字的爷节点是不是根节点+不是根节点的话,爷节点的关键字个数是否<下限,<下限的话要再次合并,直到满足要求。B树中的它的左子树所有关键字的值<当前关键字的值<它的右子树的所有关键字的值

如下图删除关键字49了之后,49原本所在的节点的关键字个数==1<下限2,则要开始补充当前节点的关键字个数。删除关键字49了之后,49原本节点的关键字只剩25,右兄弟节点(71,72)关键字个数也不宽裕,不够借。此时让当前缺关键字节点和右兄弟节点合体,并把这两个节点中间的关键字合并到一起,即(25)和(71,72)节点的中间的关键字的是70,把70放到25后边,把(71,72)放到70后边合成一个节点,此时因为从节点(70,73)扣了一个节点70,导致当前节点也不满足下限,则此时73所在节点也要分裂调整。即(73)的右兄弟节点(87,93)也不够借,也需要把这俩节点合并,并把这俩节点夹住的中间的关键字一起合并进来,才能满足节点内的关键字有顺序的大小特性,即中间的关键字为82,把中间的关键字放到当前缺关键字节点的关键字后边,即82放在73后边,右兄弟节点上的关键字跟在中间关键字后边,此时根节点上没有任何关键字了,可以把根节点删除。

 

知识回顾:

 

。。。。。。。。。。。。。。。。。。。。。。。。。 

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

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

相关文章

Linux系统基本操作指令

Linux系统基本操作指令 文章目录 Linux系统基本操作指令一、介绍二、基础设置2.1 设置ubuntu与window的共享目录2.2 ubuntu系统简单介绍 三、Linux命令及工具介绍3.1 目录管理命令(功能&#xff0c;格式&#xff0c;参数&#xff0c;系统参数)3.2 文件操作命令 四、网络命令4.1…

系统思考VS心智模式

在这张图片中&#xff0c;我们看到的是两杯相同价格的咖啡&#xff0c;它们的价格显示方式不同。一杯咖啡的原价和现价都写得很大&#xff0c;而另一杯的价格则以较小的字体呈现。这种微妙的设计差异揭示了一个有趣的心理现象——心智模式。 人们在面对同样的价格时&#xff0…

all()函数和any()函数

参考文献 在if上使用.all和.any # 中心点未改变&#xff0c;说明达到稳态&#xff0c;结束递归if (self.points new_center).all():sum self.__sumdis(result)return result, self.points, sum

Maven:依赖管理就像乐高拼装的艺术

目录 &#x1f3d7;️ 第一章&#xff1a;Maven是高级乐高玩家&#x1f50d; 依赖管理的基本单元 &#x1f9e9; 第二章&#xff1a;多模块项目——乐高巨舰组装术&#x1f31f; 为什么要拆分模块&#xff1f;&#x1f6e0;️ 父子POM配置示范 ⚔️ 第三章&#xff1a;依赖冲突…

空间数据挖掘 期末复习

前言&#xff1a;此篇复习笔记结合了课程ppt和deepseek回答进行总结&#xff0c;如有谬误恳请指正。 期末考例题 &#xff08;名词解释*10、简答*6、论述*6&#xff09; 一、名词解释 数据挖掘 过拟合&#xff08;Overfitting&#xff09; Apriori算法 决策树&#xff08;…

跳跳杆、弹跳杆、Poto stick:百年弹跳玩具的健康与使用分享(大模型改写)

跳跳杆&#xff1a;百年弹跳神器的健康争议与安全指南 &#xff08;用DeepSeek改写前一篇文章&#xff0c;可惜没有接广告&#xff0c;否则植入一些链接多好&#xff09; &#x1f50d; 一、健康功效&#xff1a;惊喜与风险并存 争议性健康主张 坊间流传跳跳杆可能具备&…

WHAT - React Native 开发 App 从 0 到上线全流程周期

文章目录 一、React Native App 开发流程总览二、各阶段详细说明需求分析 & 产品规划技术选型 & 方案确定项目初始化A. 使用 Expo&#xff08;推荐新手&#xff09;B. 使用 React Native CLI&#xff08;自由度更高&#xff09; UI 开发 功能开发&#xff08;主开发阶…

Windows11 无法发现局域网内设备解决方法

临时解决 发生问题绝大多数Windows11 24H2版本&#xff0c;该版本目前来看没有永久解决方案 初步问题可以定位在FDResPub服务问题&#xff0c;重启该服务可以短暂恢复&#xff0c;临时解决方案就是重启该服务&#xff0c;然后把网络设备右键创建快捷方式 做成批处理文件 创建…

张 心理健康咨询相关论文;AI心理咨询数字孪生:个性化风格的突破

张 心理健康咨询相关论文 EmoLLM:多模态情感理解与大型语言模型的结合 PsyDT:使用 LLM 构建具有个性化咨询风格的心理咨询师数字孪生 目前,大型语言模型 (LLM) 在心理咨询领域取得了重大进展。然而,现有的心理健康 LLM 忽略了一个关键问题,即他们没有考虑不同的心理咨…

通达信【千军趋势决策系统】幅图指标

指标功能说明 本指标基于价格波动与趋势转折点,结合K线形态分析,提供多维度买卖信号,适用于股票、期货等趋势交易场景。 核心信号解读 「横扫千军」 触发条件:短期、中期、长期趋势同时确认反转向上。 用法:趋势共振信号,提示较强多头机会,可结合成交量验证。 「出击!…

大模型LoRA微调实践

大模型LoRA微调实践 准备工作 数据集&#xff1a;采用 GitHub 上的 Chinese-medical-dialogue-data 中文医疗对话数据集 Github地址如下&#xff1a; https://github.com/Toyhom/Chinese-medical-dialogue-data 微调模型&#xff1a; Qwen 1.5B模型&#xff08;Qwen2、2.5均…

跟着AI学习C#之项目实践Day1

&#x1f9ed; 实战项目&#xff1a;博客平台系统 - Day1 &#x1f3d7;️ 目标 创建新的 ASP.NET Core 项目添加 EF Core 和 Identity 支持实现用户注册、登录功能运行并测试基本身份验证流程 &#x1f5d2;️ 任务清单 1. 创建新项目 打开 Visual Studio 或 Visual Studi…

Java面试复习指南:基础、面向对象、Java 8新特性及并发编程

Java面试复习指南&#xff1a;基础、面向对象、Java 8新特性、常用框架及并发编程 面试中&#xff0c;Java开发者常被问及多个核心技术点。本文从以下几个方面帮助考生快速复习&#xff1a; Java基础 概念解析&#xff1a;Java是一种面向对象的高级编程语言&#xff0c;具有…

微信小程序form表单手机号正则检验pattern失效

好奇怪啊&#xff0c;h5页面校验没问题&#xff0c;在微信小程序模拟器以及真机运行都失效&#xff0c;排查半天&#xff0c;记录一下 PS&#xff1a;身份证号校验也没问题&#xff0c;就手机号校验有问题&#xff0c;奇奇怪怪的 之前的写法&#xff08;在小程序上不生效&…

基于LQR的双积分小车轨迹跟踪控制系列(三)从连续到离散:双积分小车状态空间的数字实现

为什么要离散化&#xff1f; 以便在数字硬件和仿真程序中使用。 离散化的数学推导 连续状态空间&#xff1a; 双积分小车的简化形式 由于双积分小车的 A 矩阵结构简单&#xff08;A0&#xff09;&#xff0c;矩阵指数可以化简&#xff1a; Python实现&#xff08;示例代码&am…

如何在服务器终端下载百度网盘数据

使用BaiduPCS-Go在终端实现远程服务器对百度网盘数据的上传与下载流程学习 BaiduPCS-Go可用于访问和管理百度网盘文件资源的命令行客户端下载百度网盘数据至服务器从服务器中上传文件至百度网盘中BaiduPCS-Go可用于访问和管理百度网盘文件资源的命令行客户端 下载百度网盘数据…

消息队列:基本知识

定义 队列 Queue 是一种先进先出的数据结构&#xff0c;所以消费消息时也是按照顺序来消费的 消息队列看作是一个存放消息的容器&#xff0c;需要使用消息的时候&#xff0c;直接从容器中取出消息供自己使用即可 参与消息传递的双方称为 生产者 和 消费者 生产者负责发送消…

算法-动态规划-钢条切割问题

钢条切割问题是一个经典的动态规划问题&#xff0c;旨在通过切割钢条获得最大收益。以下是详细解释和解决方案&#xff1a; 问题描述 给定长度为 n 的钢条和价格表 p&#xff0c;其中 p[i] 表示长度为 i 的钢条的价格&#xff08;i 1, 2, ..., n&#xff09;。目标&#xff…

DeepSeek:中国AI开源先锋的技术突破与行业革新

在人工智能技术迅猛发展的浪潮中&#xff0c;DeepSeek&#xff08;深度求索&#xff09;作为中国AI领域的新锐力量&#xff0c;凭借其创新的技术路线和开源策略&#xff0c;正在全球AI舞台上崭露头角。这家由知名量化投资机构幻方量化支持的AI公司&#xff0c;自2023年7月成立以…

cmake:动态链接库(dll)的调用

如题,动态链接库的调用和静态链接库有所不同,现将步骤整理如下。 动态链接库文件 正常情况下,编译的动态链接库有五个生成文件和对应的头文件,在调用中,使用dll文件,lib文件 和头文件。编译生成动态库的步骤和配置见C++:动态链接库的编写,__declspec 用法详解-CSDN博…