c++实现B树(下)
书接上回小吉讲的是B树的搭建和新增方法的实现(blog传送门🚪:B树实现上)(如果有小可爱对B树还不是很了解的话,可以先看完上一篇blog,再来看小吉的这篇blog)。那这一篇主要讲的是B树中删除操作的实现。
在看小吉的数据结构与算法(c++实现)系列博客中,各位小可爱们应该能发现,其实在实现一个数据结构时,删除操作普遍比新增操作要难。小吉浅浅预告一下B树的删除操作可以说是天花板级别的难。但是各位小可爱们不要怕,跟着小吉的博客看下去B树删除易如反掌(哈哈,夸张了🤣)
在实现B树删除操作之前,小吉先在这声明一下:B树的删除是删除某个节点的key并不是将节点删除(无需使用delete)
九个成员方法
在正式分析B树删除之前,先要实现9个方法(不要害怕,这九个方法都非常简单),这九个方法在后期实现删除操作代码时大有用处(可以小小期待一下)
int removeKey(int index);//移除指定index处的key
int removeRightmostKey();//移除最右边的key
Node* removeChild(int index);//移除指定index处的child
Node* removeLeftmostChild();//移除最左边的child
Node* removeRightmostChild();//移除最右边的child
Node* childLeftSibling(int index);//index孩子处左边的兄弟
Node* childRightSibling(int index);//index孩子处右边的兄弟
void moveToTarget(Node* target);//复制当前节点的所有key和child到target
这些方法都定义在Node节点类中,这些方法都比较简单,小吉在这就不详细讲解了,直接上代码。
int Node::removeKey(int index)
{int t = _keys[index];_keys.erase(_keys.begin() + index);KeyNumber--;return t;
}int Node::removeLeftmostKey()
{return removeKey(0);
}int Node::removeRightmostKey()
{return removeKey(KeyNumber - 1);
}Node* Node::removeChild(int index)
{Node* t = _children[index];_children.erase(_children.begin() + index);return t;
}Node* Node::removeLeftmostChild()
{return removeChild(0);
}Node* Node::removeRightmostChild()
{return removeChild(KeyNumber - 1);
}Node* Node::childLeftSibling(int index)
{return index > 0 ? _children[index - 1] : nullptr;
}Node* Node::childRightSibling(int index)
{return index == KeyNumber ? nullptr : _children[index + 1];
}void Node::moveToTarget(Node* target)
{int start = target->KeyNumber;if (!this->_leaf){for (int i = 0; i <= this->KeyNumber; i++){target->_children[start + i] = this->_children[i];}}for (int i = 0; i < this->KeyNumber; i++){target->_keys[target->KeyNumber++] = this->_keys[i];}
}
搭建remove删除方法的架子
首先明确一点要删除节点的前提是要先找到节点才能进行删除操作,所以remove方法最初的雏形就是找要删除的节点(采用递归进行查找)
找节点的思路在上一篇blog新增节点时有体现,小吉在这也不详细讲解了,直接上代码👇
void BTree::remove(int key)
{doremove(_root, key,0);
}void BTree::doremove(Node* node, int key)
{int i = 0;while (i < node->KeyNumber){if (node->_keys[i] >= key){break;}i++;}if (node->_leaf)//叶子节点{if (i < node->KeyNumber && node->_keys[i] == key)//i找到:代表待删除key的索引{}else//i没找到{return;}}else//非叶子节点{if (i < node->KeyNumber && node->_keys[i] == key)//i找到:代表待删除key的索引{}else//i没找到:代表第i个孩子继续查找{doremove(node,node->_children[i], key,i);}}
}
remove删除情况分类
主要分为以下4种情况:
case1:当前节点是叶子节点,没找到
case2:当前节点是叶子节点,找到了
case3:当前节点是非叶子节点,没找到
case4:当前节点是非叶子节点,找到了
叶子节点
分析当前节点是叶子节点的情况,这种情况比较简单,找到就删除当前节点要删除的key值(调用前面实现的九个小方法中的removeKey方法即可),没找到说明B树中没有我们要删除的key值,直接return退出即可。
if (node->_leaf)//叶子节点{if (i < node->KeyNumber && node->_keys[i] == key)//i找到:代表待删除key的索引{node->removeKey(i);}else//i没找到{return;}}
非叶子节点
没找到:递归继续寻找
找到:1.找后继的key 2.替换待删除的key 3.删除后继的key
else//非叶子节点{if (i < node->KeyNumber && node->_keys[i] == key)//i找到:代表待删除key的索引{//1.找到后继keyNode* s = node->_children[i + 1];while (!s->_leaf){s = s->_children[0];}int skey = s->_keys[0];//2.替换待删除keynode->_keys[i] = skey;//3.删除后继keydoremove(node,node->_children[i + 1], skey,i+1);}else//i没找到:代表第i个孩子继续查找{doremove(node,node->_children[i], key,i);}}
删除完不平衡的处理
在删除节点完可能存在删除后key数目<下限(根节点除外),导致不平衡的情况
对平衡的调整又可以分为一下三种情况:
case1:左边富裕,右旋
case2:右边富裕,左旋
case3:两边都不够借,向左合并
void balance (Node* parent,Node* x,int i) //x为要调整的节点,i为被调整孩子的索引
注: 为了实现平衡函数的传参,doremove方法还要再加上两个参数void BTree::doremove(Node* parent,Node* node, int key,int index)//index被删除节点的索引
左边富裕,右旋
右旋:1)父节点中前驱key旋转下来(前驱key是要删除节点的前驱)
2)left中最大的孩子换爹(被调整节点的左兄弟不为叶子节点要执行这一步)
2)left中最大的的key旋转上去
下面👇是代码实现旋转的过程:
void BTree::balance(Node* parent, Node* x, int i)
{Node* left = parent->childLeftSibling(i);if (left != nullptr && left->KeyNumber > MIN_KEYNUMS){//左边富裕,右旋x->insertKey(0, parent->_keys[i - 1]);if (!left->_leaf){x->insertChild(0, left->removeRightmostChild());}parent->_keys[i-1]= left->removeRightmostKey();return;}
}
右边富裕,左旋
左旋:1)父结点中后继key旋转下来(后继key是要删除节点的后继)
2)right中最小的孩子换爹(被调整节点的右兄弟不为叶子节点时要执行这一步)
3)right中最小的key旋转上去
和左边富裕,右旋的情况类似,小吉这里就不画图了,直接上代码
void BTree::balance(Node* parent, Node* x, int i)
{Node* right = parent->childRightSibling(i);if (right != nullptr && right->KeyNumber > MIN_KEYNUMS){//右边富裕,左旋x->insertKey(x->KeyNumber, parent->_keys[i]);if (!right->_leaf){x->insertChild(x->KeyNumber+1, right->removeLeftmostChild());}parent->_keys[i] = right->removeLeftmostKey();return;}
两边都不够借,向左合并
case1:被调整节点有左兄弟,往左兄弟处合并
case2:被调整节点没有左兄弟,父节点和右边的兄弟向自己处合并
case1:
case2:
代码呈现👇:
//两边都不够借,向左合并if (left != nullptr){//向左兄弟合并parent->removeChild(i);left->insertKey(left->KeyNumber, parent->removeKey(i - 1));x->moveToTarget(left);}else{//向自己合并parent->removeChild(i + 1);x->insertKey(x->KeyNumber, parent->removeKey(i));right->moveToTarget(x);}
到这里,B树删除的所有涉及到的知识点都已经讲完了,下面小吉给大家提供一个B树删除的测试代码。
B树删除的测试代码
void testRemove()
{BTree tree(3);for (int i = 1; i <= 6; i++){tree.put(i);}tree.remove(2);Node* root = tree._root;Node* leftchild = root->_children[0];cout << root->_keys[0] << endl;for (int i = 0; i < leftchild->KeyNumber; i++){cout << leftchild->_keys[i] << ' ';}cout << endl;
}
到这里,这篇blog要结束了,有点小长,也有点小难,可能一次性看完对一些小可爱们有难度,不要急,慢慢看,多给自己一点时间❤️
(其实这篇博客从9月份写到了11月🤣,可以说是小吉已经发表的博客中最长的一篇了,也是最难的一篇,原计划打算九月份写完的,中途去备考了一下软设,所以就一直拖到现在才写完,不好意思耽误了这么久了😖)
&emps;最后,创作不易(这篇blog小吉真的写了很久),还望大家多多支持(点赞收藏关注小吉🌹)
相关文章:

c++实现B树(下)
书接上回小吉讲的是B树的搭建和新增方法的实现(blog传送门🚪:B树实现上)(如果有小可爱对B树还不是很了解的话,可以先看完上一篇blog,再来看小吉的这篇blog)。那这一篇主要讲的是B树中…...

外星人入侵
学习于Python编程从入门到实践(Eric Matthes 著) 整体目录:外星人入侵文件夹是打包后的不必在意 图片和音效都是网上下载的 音效下载网站:Free 游戏爆击中 Sound Effects Download - Pixabay 运行效果:可以上下左右移…...

【数据仓库】hbase的安装与简单操作
HBase 是一个分布式的、面向列的开源数据库,它支持大规模数据存储,并且是 Hadoop 生态系统的一部分。HBase 能够在廉价的硬件上运行,并提供对大量数据的随机、实时读写访问。下面是关于如何在 Linux 系统上安装 HBase 以及进行一些基本操作的…...

为什么RNN(循环神经网络)存在梯度消失和梯度爆炸?
1️⃣ 原理分析 RNN前向传播的公式为: x t x_t xt是t时刻的输入 s t s_t st是t时刻的记忆, s t f ( U ⋅ x t W ⋅ s t − 1 ) s_tf(U\cdot x_tW\cdot s_{t-1}) stf(U⋅xtW⋅st−1),f表示激活函数, s t − 1 s_{t-1} …...

【数据库】数据库迁移的注意事项有哪些?
数据库迁移是一个复杂且关键的过程,需要谨慎处理以确保数据的完整性和应用程序的正常运行。以下是一些数据库迁移时需要注意的事项: 1. 充分的前期准备 1.1 评估迁移需求 明确目标:确定迁移的具体目标,例如添加新字段、修改现…...

MQTT协议解析 : 物联网领域的最佳选择
1. MQTT协议概述 1.1 MQTT协议是什么 MQTT : Message Queuing Telemetry Transport 模式 : 发布 / 订阅主题优点 : 代码量小、低带宽、实时可靠应用 : 物联网、小型设备、移动应用MQTT 常用端口 : 1883 MQTT是一个网络协议,和HTTP类似,因为轻量简单&…...

pycharm中from[本地包]import文件/模块出现问题(最最最全方法!)
1.通过PYTHONPATH的方法在此处将路径添加上,能够让IDE访问得到。 2.通过选中目标文件所在的文件的文件夹单击右键,如下图所示可以看到下方的mark directory as选项中存在 存在excluded,选择此项可解决问题,如果仍有问题可以尝试其…...

MongoDB在现代Web开发中的应用
💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 MongoDB在现代Web开发中的应用 MongoDB在现代Web开发中的应用 MongoDB在现代Web开发中的应用 引言 MongoDB 概述 定义与原理 发展…...

Python Bokeh 数据可视化教程
Python Bokeh 数据可视化教程 引言 在数据科学和分析的过程中,数据可视化是一个至关重要的环节。它不仅能帮助我们更好地理解数据,还能在报告和展示中提升数据的可读性和吸引力。Python 作为数据科学的主要工具之一,提供了多种数据可视化库…...

(一)<江科大STM32>——软件环境搭建+新建工程步骤
一、软件环境搭建 (1)安装 Keil5 MDK 文件路径:江科大stm32入门教程资料/Keil5 MDK/MDK524a.EXE,安装即可,路径不能有中文。 (2)安装器件支持包 文件路径:江科大stm32入门教程资料…...

内存大小的单位转换
计算机中内存大小的单位转换通常是按照以下规则进行的: 基本单位 1 字节 (Byte) 8 位 (bit) 常见的内存单位及转换关系 1 字节 (Byte) 8 位 (bit)1 千字节 (KB) 1,024 字节 (B)1 兆字节 (MB) 1,024 千字节 (KB) 1,024 * 1,024 字节 (B)1 吉字节 (GB) 1,02…...

如何在 Spring MVC 中使用 `@PostMapping`? 如何在 Spring MVC 中使用 `@PutMapping`?
PostMapping 和 PutMapping 是 Spring MVC 中用于处理 HTTP POST 和 PUT 请求的注解。它们分别对应 HTTP 协议中的 POST 和 PUT 方法,通常用于创建和更新资源。下面详细解释如何在 Spring MVC 中使用这两个注解。 1. 使用 PostMapping PostMapping 注解用于处理 H…...

AIGC Agent(智能体)应用开发高级工程师实战培训 —— 线上8周系统教学课程学习路线图
🎯 课程目标 系统掌握AIGC核心技术:学员将通过项目驱动学习,从文本生成、图像创意到智能体开发,全面进阶AIGC技术,探索其在营销、教育、数据处理、知识管理等领域的实际应用。构建AIGC智能体服务体系:学成…...

GDSC、CTRP数据库学习
GDSC 写在前面下载数据疑问1.GDSC、CTRP数据里有TCGA配套的数据?数据类型?CTRP原始数据如何处理 写在前面 开此贴做GDSC的数据分析记录 下载数据 GDSC官网:http://www.cancerrxgene.org/ 由于在官网下载数据过于麻烦,于是我使用…...

【嵌入式】ESP32开发(一)ESP-IDF概述
文章目录 1 前言2 IDF环境配置3 在VS Code中使用IDF3.1 使用ESP-IDF例程3.2 底部按钮的作用【重要!】3.3 高级用法4 ESP-IDF框架分析5 从零开始创建一个项目5.1 组件(component)6 主要参考资料7 遇到的一些问题与解决办法8 对于ESP-IDF开发的一些感受1 前言 对于ESP32的开发…...

最新6.7分非肿瘤纯生信,使用机器学习筛选慢阻肺中的关键基因。机器学习在非肿瘤生信文章中正火,可重复!
关于非肿瘤生信,我们也解读过很多,主要有以下类型 1 单个疾病WGCNAPPI分析筛选hub基因。 2 单个疾病结合免疫浸润,铁死亡,自噬等基因集,机器学习算法等。 3 两种相关疾病联合分析,包括非肿瘤结合非肿瘤&…...

vue 提交表单抹除字段为空的数据
使用背景 在配合后端post请求接口的时候 仅需要将有值的字段传入接口中 关键代码 cleanDataObj(obj) {Object.keys(obj).forEach((key) > {if (obj[key] ) {delete obj[key]}})},demo如下 export default {data() {return {demoObject:{name:小花,sex:,hobb…...

web实验3:虚拟主机基于不同端口、目录、IP、域名访问不同页面
创建配置文件: 创建那几个目录及文件,并且写内容: 为网卡ens160添加一个 IPv4 地址192.168.234.199/24: 再重新激活一下网卡ens160: 重启服务: 关闭防火墙、改宽松模式: 查看nginx端口监听情况:…...

英伟达Isaac Manipulator产品体验
相关配置 Isaac Manipulator3.1.0Isaac Sim4.2.0Ubuntu20.04GPURTX 4090 LaptopCPUI9 13900HXMem64GB 过程记录与反馈 GPU加速效果 请描述您在使用Isaac Manipulator时,调用cuMotion加速库来进行机器人运动规划和轨迹优化等任务的步骤和过程,并记录任…...

网安加·百家讲坛 | 仝辉:金融机构鸿蒙应用安全合规建设方案
作者简介:仝辉,北京娜迦信息科技发展有限公司攻防安全负责人,深耕移动应用安全领域十余年,获得过CISP、CISSP、OSCP、PMP、CCRC-CIASW等相关证书,参与多项移动应用安全标准起草,参与华为、平安集团、中国移…...

PHP Session
PHP Session PHP Session 是一种在 PHP 中用于跟踪用户会话的技术。会话允许在用户浏览网站时存储和访问用户信息。本文将详细介绍 PHP Session 的工作原理、如何创建和销毁会话、会话的安全性和最佳实践。 什么是 PHP Session? 在 Web 开发中,HTTP 是一种无状态的协议,这…...

泷羽sec学习打卡-Linux基础2
声明 学习视频来自B站UP主 泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 关于Linux的那些事儿-Base2 一、Linux-Base2linux有哪些目录呢?不同目录下有哪些具体的文件呢…...

# 【STM32F1】——无线收发模块RF200与串口通信
【STM32F1】——无线收发模块RF200与串口通信 一、简介 本篇主要对调试无线收发模块RF200的过程进行总结,实现了以下功能。 串口普通收发:使用STM32F103C8T6的USART2串口接收中断,实现两个无线收发模块RF200间的通信。二、RF200介绍 电压:3.4-5.5V工作频率:418~455MHz发…...

计算机网络:运输层 —— TCP 协议概述与 TCP 报文段首部格式
文章目录 基本概念主要特点和功能TCP报文段的首部格式字段标志位扩展首部 传输控制协议(Transmission Control Protocol,TCP)协议是互联网上最常用的传输层协议之一,它负责提供可靠的端到端数据传输服务。TCP 协议采用连接导向的通…...

python正则表达式和递归
一、正则表达式 1.基础匹配 学习目标:了解什么是正则表达式,掌握re模块的基础使用 就是一种规则的定义,通过规则去验证给定的目标是否符合定义的规则。 正则的三个基础方法 match match是匹配开头,开头有python就算匹配成功&a…...

JAVA后端生成图片滑块验证码 springboot+js完整案例
前言 现在大部分网部都是图片滑块验证码,这个得要与后端联动起来才是确保接口安全性 通过我们系统在发送手机短息时都会选进行滑块验证,但是我们要保证发送短息接口的全安,具体路思如下 那么这个滑块的必须是与后端交互才能保证安全性&…...

Spring Boot中的自动装配机制
文章目录 1. 什么是自动装配?2. 自动装配是如何工作的?3. 如何开启自动装配?4. 自动装配的注意事项5. 结语推荐阅读文章 在Spring Boot的世界里,自动装配(Auto-configuration)就像春风拂面,轻轻…...

Brave127编译指南 Windows篇:配置Git(四)
1. 概述 在Brave浏览器的开发过程中,Git作为核心版本控制工具扮演着不可或缺的角色。作为当今最广泛使用的分布式版本控制系统,Git为开发者提供了强大的源码管理能力。通过Git,您可以轻松追踪代码变更、管理不同版本,并与其他开发…...

mysql数据库(五)多表查询
多表查询 文章目录 多表查询一、链表查询1.1交叉连接1.2 内连接1.3 左连接1.4 右连接1.5 全连接1.6 例子 二、子查询2.1 in与not in2.2 any/some2.3 all2.4 比较运算符2.5 exists 三、例子 查询中使用的表如下所示 ------------ | id | name | ------------ | 1 | IT | …...

【go从零单排】JSON序列化和反序列化
🌈Don’t worry , just coding! 内耗与overthinking只会削弱你的精力,虚度你的光阴,每天迈出一小步,回头时发现已经走了很远。 📗概念 在 Go 语言中,处理 JSON 数据主要依赖于 encoding/json 包。这个包提…...