B+树的设计步骤

news2024/11/16 3:35:26

1.节点的结构(如下图)

        (1)键值对--key是标识;value是存储的具体数据

        (2)节点的子节点--存储的是具体的子节点

        (3)节点的后节点--标记后一个节点

        (4)节点的前节点--标记前一个节点

        (5)节点的父节点--标记父节点是哪个

2.存储的规则

2.1存储第一条数据,并标记根节点和头结点。

2.2单个节点

2.2.1.没有超过设定的阶数

当存储第二和三个数据时,首先判断是否是最后一个结点或者要插入的键值对的键的值是否小于下一个结点的的键的最小值。如果是则再判断有没有超过设定的阶数,没有则将将数据直接插入到当前结点。当前的结点是最后一个结点并且没有超过设定的阶数,因此直接将二三个数据直接插入到当前的结点当中 。             

2.2.2.超过阶数(分裂)

在存储第四个数时,首先判断是否是最后一个结点或者要插入的键值对的键的值是否小于下一个结点的的键的最小值。如果是再判断是否超过设定的阶数了,超过了则取出原来key-value 集合中间位置的下标mid并获得中间位置的键midKey。构造一个新的键值对midKeyAndValue存储(中间位置的键,空串),然后分别将中间位置的左边封装成集合对象leftKeyAndValue,并将左边的数存储到leftKeyAndValue中;中间位置的右边封装成集合对象rightKeyAndValue,再判断当前节点是否有叶子结点,如果有则将中间位置后的数据(不包含中间位置的数据)存储到rightKeyAndValue中;如果没有则将从中间位置开始右边的数据保存到rightKeyAndValue中。分别对左右两个集合对象进行排序处理。以mid为界限将当前结点分裂成两个结点分别是:前节点leftNode,后节点rightNode;前指针的节点的结构为:数据(leftKeyAndValue),子节点(null),前指针(当前节点的左节点),后指针(rightNode),父节点(当前结点的父节点);此时将头节点重置为前节点leftNode;新建一个子节点childNode并将前节点leftNode和后节点rightNode添加进去,然后构造一个父节点parentNode结构为:子节点(childNode),键值对(midKeyAndValue),前节点(null),后节点(null),父节点(null)。并将子节点与父节点进行关联。将当前父节点设置为根节点。此时就转变成“一父二子”了

                                                                        

2.3一夫二子

2.3.1.没有超过设定的阶数

 存储第五个数的时候,首先以L1节点为head判断是否是最后一个结点或者要插入的键值对的键的值是否小于下一个结点的的键的最小值。如果是再判断是否超过设定的阶数了,根据上图可以看出无论数据存储到哪个子节点都不会超过设定的阶数,因此可以将数据直接存储到L1节点;如果不是最后一个结点或者要插入的键值对的键的值大于下一个结点的的键的最小值,此时移动指针,将R1作为依据再进行判断是否是最后一个结点或者要插入的键值对的键的值是否小于下一个结点的的键的最小值,此时肯定符合条件的,再判断是否超过设定的阶数了,此时的场景不会超过设定的阶数,因此将数据直接添加到R1中,并排序处理。

     因此会有下图这两种情况

存储第六个数据的时候有百分之五十的几率不会超过设定的阶数存储的过程跟存储第五个数的过程一样。

结果如下图两种情况

        2.3.2超过设定的阶数

存储第六个数据的时候有百分之五十的可能性会超过阶数,如下图(2.3-5和2.3-6),在添加数据的时候首先以L1节点为head判断是否是最后一个结点或者要插入的键值对的键的值是否小于下一个结点的的键的最小值。

1.如果是再判断是否超过设定的阶数了,此时设定的场景是要超过设定的阶数,先取出L1节点的key-value 集合中间位置的下标mid并获得中间位置的键midKey。构造一个新的键值对midKeyAndValue存储(中间位置的键,空串),然后分别将中间位置的左边封装成集合对象leftKeyAndValue,并将左边的数存储到leftKeyAndValue中;中间位置的右边封装成集合对象rightKeyAndValue,再判断当前节点是否有叶子结点,如果有则将中间位置后的数据(不包含中间位置的数据)存储到rightKeyAndValue中;如果没有则将从中间位置开始右边的数据保存到rightKeyAndValue中。分别对左右两个集合对象进行排序处理。以mid为界限将当前结点分裂成两个结点分别是:前节点leftNode,后节点rightNode;前指针的节点的结构为:数据(leftKeyAndValue),子节点(null),前指针(当前节点的左节点),后指针(rightNode),父节点(当前结点的父节点),新建一个子节点集合childNodes并分别将前节点leftNode,后节点rightNode添加进去;如果头结点是当前要分隔的节点则将头节点重置为前节点leftNode,获取到当前L1节点的父节点parentNode,并获取到父节点的所有子节点,将这些子节点全部添加到子节点集合childNodes中,然后删除当前的L1节点,然后将子节点重置成新的子节点集合childNodes;继续以父节点为依据判断是否超过设定的阶数了,此时没有超过阶数,将键值对midKeyAndValue直接保存到当前的父节点中,并进行排序操作,此时就变成“一夫三子”了如图(2.3-7);

2.如果不是最后一个结点或者要插入的键值对的键的值大于下一个结点的的键的最小值,此时移动指针,将R1作为依据再进行判断是否是最后一个结点或者要插入的键值对的键的值是否小于下一个结点的的键的最小值,此时肯定符合条件的,再判断是否超过设定的阶数了,此时设定的场景是要超过设定的阶数,先取出R1节点的key-value 集合中间位置的下标mid并获得中间位置的键midKey。构造一个新的键值对midKeyAndValue存储(中间位置的键,空串),然后分别将中间位置的左边封装成集合对象leftKeyAndValue,并将左边的数存储到leftKeyAndValue中;中间位置的右边封装成集合对象rightKeyAndValue,再判断当前节点是否有叶子结点,如果有则将中间位置后的数据(不包含中间位置的数据)存储到rightKeyAndValue中;如果没有则将从中间位置开始右边的数据保存到rightKeyAndValue中。分别对左右两个集合对象进行排序处理。以mid为界限将当前结点分裂成两个结点分别是:前节点leftNode,后节点rightNode;前指针的节点的结构为:数据(leftKeyAndValue),子节点(null),前指针(当前节点的左节点),后指针(rightNode),父节点(当前结点的父节点),新建一个子节点集合childNodes并分别将前节点leftNode,后节点rightNode添加进去;如果头结点是当前要分隔的节点则将头节点重置为前节点leftNode,获取到当前L1节点的父节点parentNode,并获取到父节点的所有子节点,将这些子节点全部添加到子节点集合childNodes中,然后删除当前的R1节点,然后将子节点重置成新的子节点集合childNodes;继续以父节点为依据判断是否超过设定的阶数了,此时没有超过阶数,将键值对midKeyAndValue直接保存到当前的父节点中,并进行排序操作,此时就变成“一夫三子”了如图(2.3-8)

存储第七个数据时有两种情况

1.如果存储第六个数据时没有分裂,则此时存储定会分裂如下图(2.3.9-2.3.12);分裂过程与第六次存储数据需要分裂的过程一样,结果如下图

2.如果存储第六个数据时分裂了,则此时定不会分裂结果入下图(2.3.13-2.3.16),

首先分别以图2.3-7的L2节点和2.3-8的L1节点为head判断是否是最后一个结点或者要插入的键值对的键的值是否小于下一个结点的的键的最小值。

(1).如果是再判断是否超过设定的阶数了,根据上图可以看出无论数据存储到哪个子节点都不会超过设定的阶数,因此可以将数据直接存储到第一个节点;

(2).如果不是最后一个结点或者要插入的键值对的键的值大于下一个结点的的键的最小值,此时移动指针,将第二个作为依据再进行判断是否是最后一个结点或者要插入的键值对的键的值是否小于下一个结点的的键的最小值,如果是则判断是否超过设定的阶数,此场景不会超过阶数,直接将数据存储到第二个节点的键值对当中;

(3).如果还不是最后一个结点或者要插入的键值对的键的值大于下一个结点的的键的最小值,此时移动指针,将第三个作为依据再进行判断是否是最后一个结点或者要插入的键值对的键的值是否小于下一个结点的的键的最小值, 再判断是否超过设定的阶数了,此时的场景不会超过设定的阶数,因此将数据直接添加到第三个节点中,并排序处理。

2.4一父三子

                2.4.1 三个子节点的数,要么都满,要么部分满         

存储更多数据的时候,三子节点的键值对的数据有以下两种情况

1.都满,最少再添加四个数据才会进行分裂(如图2.4.1)分裂成一父四子(如图  2.4-3)

2.部分满,再上面的基础上最少添加两个数据,就会出现部分满的情况(如图2.4-2),此时的情况是需要将满的节点进行分裂,过程与前面分裂过程一样,变成一父四子(如图2.4-4)

 

2.5一父四子 

      2.5.1 四个子节点的数,要么都满,要么部分满   

部分满跟都满都会使得节点再次分裂,分裂成一父二子的情况

在添加数据的时候首先以左边第一个节点为head判断是否是最后一个结点或者要插入的键值对的键的值是否小于下一个结点的的键的最小值。

1.如果是再判断是否超过设定的阶数了,此时设定的场景是要超过设定的阶数,先取出当前节点的key-value 集合中间位置的下标mid并获得中间位置的键midKey。构造一个新的键值对midKeyAndValue存储(中间位置的键,空串),然后分别将中间位置的左边封装成集合对象leftKeyAndValue,并将左边的数存储到leftKeyAndValue中;中间位置的右边封装成集合对象rightKeyAndValue,再判断当前节点是否有叶子结点,如果有则将中间位置后的数据(不包含中间位置的数据)存储到rightKeyAndValue中;如果没有则将从中间位置开始右边的数据保存到rightKeyAndValue中。分别对左右两个集合对象进行排序处理。以mid为界限将当前结点分裂成两个结点分别是:前节点leftNode,后节点rightNode;前指针的节点的结构为:数据(leftKeyAndValue),子节点(null),前指针(当前节点的左节点),后指针(rightNode),父节点(当前结点的父节点),新建一个子节点集合childNodes并分别将前节点leftNode,后节点rightNode添加进去;如果头结点是当前要分隔的节点则将头节点重置为前节点leftNode,获取到当前节点的父节点parentNode,并获取到父节点的所有子节点,将这些子节点全部添加到子节点集合childNodes中,然后删除当前节点,然后将子节点重置成新的子节点集合childNodes;

2.继续以父节点为依据判断是否超过设定的阶数了,此时超过阶数,超过了则取出原来key-value 集合中间位置的下标mid并获得中间位置的键midKey。构造一个新的键值对midKeyAndValue存储(中间位置的键,空串),然后分别将中间位置的左边封装成集合对象leftKeyAndValue,并将左边的数存储到leftKeyAndValue中;中间位置的右边封装成集合对象rightKeyAndValue,再判断当前节点是否有叶子结点,如果有则将中间位置后的数据(不包含中间位置的数据)存储到rightKeyAndValue中;如果没有则将从中间位置开始右边的数据保存到rightKeyAndValue中。分别对左右两个集合对象进行排序处理。以mid为界限将当前结点分裂成两个结点分别是:前节点leftNode,后节点rightNode;前指针的节点的结构为:数据(leftKeyAndValue),子节点(null),前指针(当前节点的左节点),后指针(rightNode),父节点(当前结点的父节点);判断当前结点是否有孩子节点,此场景是有孩子节点的,获取到所有孩子节点存储在nodes集合中,并新建两个集合leftNodes与rightNodes分别存储左节点的子节点与右节点的子节点,通过遍历取得当前孩子节点的最大键值,小于mid的键的数是左节点的子节点;大于mid的键的数是右节点的子节点,将leftNodes添加为leftNode的子节点;将rightNodes添加为rightNode的子节点。此时将头节点重置为前节点leftNode;新建一个子节点childNode并将前节点leftNode和后节点rightNode添加进去;然后判断当前结点是否有父节点,此时有父节点,获取到当前节点的父节点parentNode,并获取到父节点的所有子节点,将这些子节点全部添加到子节点集合childNodes中,然后删除当前的节点,然后将子节点重置成新的子节点集合childNodes;继续以父节点为依据判断是否超过设定的阶数了,此时没有超过阶数,将键值对midKeyAndValue直接保存到当前的父节点中,并进行排序操作。最终效果如下图所示()

 

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

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

相关文章

JSP实现自定义标签【上】

目录 一、基础概念 1、标签语言的形式或结构 2、分类 二、自定义标签的开发及步骤 三、标签生命周期 1、返回值 四、案例 1、if 2、out 一、基础概念 JSP自定义标签是一种扩展JSP标记语言的方法。通过自定义标签,我们可以将自定义功能封装在一个独立的标签…

# rust abc(6): 字符串的简单使用

文章目录 1. 目的2. 数据类型2.1 str 类型2.2 标准库 String 类型 3. 常用 API3.1 len() 方法3.2 is_empty() 方法3.3 starts_with() 方法3.4 find() 方法 4. References 1. 目的 学习 Rust 语言中的字符串, 包括数据类型, 常用 API。 2. 数据类型 Ru…

新手入门:从零搭建vue3+webpack实战项目模板

搭建一个 vue3 webpack5 element-plus 基本模板 (vue3 webpack5 从零配置项目)。 本项目结构可以作为实战项目的基本结构搭建学习,作为刚学习完vue还没有实战项目经验的小伙伴练习比较合适。 项目地址: GitHub:ht…

如何将手写笔记转换成电子版格式?

记笔记是一种非常有效的学习方法。它不仅可以帮助我们加深对所学内容的理解,还能让我们收集更多有用的信息,以方便后续的查看和复习。不过,用传统的纸质笔记本记录笔记存在一定的弊端,比如说不易保存、不易携带等等。所以&#xf…

Mac下的java.io.FileNotFoundException: ~/Desktop/a.sql (No such file or directory)

【问题】: 今天在运行一个文件读取的Demo时,报如下错误: java.io.FileNotFoundException: ~/Desktop/a.sql (No such file or directory)如下图所示 : 可是这个文件命名可以通过终端窗口访问到啊? 【解决方案】&#xff…

STM32外设系列—HC-SR04(超声波)

文章目录 一、超声波测距基本原理二、超声波传感器简介三、HC-SR04测距实现思路四、超声波测距程序实现4.1 HC-SR04初始化程序4.3 TIM开关程序4.4 获取定时时间4.5 计算测量距离4.6 宏定义 五、应用实例六、拓展应用 一、超声波测距基本原理 超声波测距的原理非常简单&#xf…

高压放大器在压电陶瓷驱动器中的应用

高压放大器是一种将低电压信号放大成高电压信号的电子设备。它广泛运用于各种领域,如医疗、工业、军事以及科学研究。压电陶瓷驱动器是一种利用压电效应来驱动机械运动的装置。这两种设备经常被用于控制和操作许多不同类型的系统。 压电陶瓷是一种能够将电能转化为机…

监控摄像头的像素200万,400万,800万都是什么意思,200万像素、400万像素、800万像素是如何换算出来的?

一、像素 像素(Pixel)是用来表示图像分辨率的单位,数字越大,表示图像中的细节可以更精细地展现。当我们谈论监控摄像头的像素时,通常指的是摄像头图像传感器上的像素数量。像素的数量可以通过传感器上的横向像素数乘以…

win如何使用OpenSSL生成自签名证书,使 http 升级为 https

win如何使用OpenSSL生成自签名证书,使 http 升级为 https 前言 HTTPS其实就是HTTP over SSL,也就是让HTTP连接建立在SSL安全连接之上。 创建自签名证书需要安装openssl。参考本文安装OpenSSL部分。 使用OpenSSL生成自签名证书的步骤:参考…

python spider 爬虫 之 Selenium 系列 (-) Selenium

京东的 seckill 秒杀 专区 用 urllib 是获取不到的 回顾一下urllib 爬虫 # urllib 爬虫 from urllib import request headers {} url # 请求定制 req request(urlurl, headers headers) # 模拟请求 response request(req) content response.read().decode(utf-…

windows下安装Visual Studio + CMake+OpenCV + OpenCV contrib

目录 1 安装visual studio 2 安装CMake 3 OpenCV源码安装 3.1 OpenCV源码下载 3.2 OpenCV contrib源码下载 3.3 安装OpenCV 3.4 安装OpenCV-crontrib 3.5 VS生成代码 4 环境配置 最近在研究windows系统上部署安装目标检测算法,需要用到OpenCV软件&#xff…

智能指针+拷贝构造+vector容器+多态引起的bug

今天在调试一段代码的时候,VC编译提示: error C2280: “T485CommCtrlPara::T485CommCtrlPara(const T485CommCtrlPara &)”: 尝试引用已删除的函数 函数执行部分如下: 看意思是这个pComm485Pro已经消亡了,后续push_back到ve…

高速电路设计系列分享-信号链精度分析(中)

目录 概要 整体架构流程 技术名词解释 技术细节 1.直流无源误差 小结 概要 提示:这里可以添加技术概要 在任何设计中,信号链精度分析都可能是一项非常重要的任务,必须充分了解。之前, 我们讨论了在整个信号链累积起来并且最终会…

统一日志处理----AOP/面向切面编程

AOP Aspect Oriented Programing:面向切面编程 AOP是对OOP的补充,进一步提高编程的效率 AOP的常见使用场景有:权限检查、记录日志、事务管理等 如下图所示结构,每个模块都含有相同的系统需求,而这些需求和模块本身的功…

Flutter进阶-动画详解

目录 动画类别 一、隐式(全自动)动画 二、显式动画(手动控制) 三、其他动画(CustomPainter) 动画类别 Flutter 中有多种类型的动画: 隐式动画:通过更改部件属性自动触发的预定义动画,例如 …

什么是cookie

1、cookie是什么 Cookie,有时也用其复数形式Cookies。类型为“小型文本文件”,是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存…

Python强类型编程

Python是一门强类型的动态类型语言,具体如下特性: 可以动态构造脚本执行、修改函数、对象类型结构、变量类型但不允许类型不匹配的操作 第一个例子体现动态性:用字符串直接执行代码,动态构建了一个函数并执行,甚至给…

力扣744.寻找比目标字母大的最小字符(java暴力查找法,二分查找法)

题目描述: 给你一个字符数组 letters,该数组按非递减顺序排序,以及一个字符 target。letters 里至少有两个不同的字符。 返回 letters 中大于 target 的最小的字符。如果不存在这样的字符,则返回 letters 的第一个字符。 [外链…

岭回归(Ridge)不同alpha值对归回结果的影响

对于有些矩阵,矩阵中某个元素的一个很小的变动,会引起最后计算结果误差很大,这种矩阵称为“病态矩阵”。有些时候不正确的计算方法也会使一个正常的矩阵在运算中表现出病态。对于高斯消去法来说,如果主元(即对角线上的…

亚马逊测评:如何有效使用IP和养号设备环境

随着网络科技的崛起,越来越多的本土企业入驻亚马逊电子商务平台上,这导致了对产品评价需求的激增。然而,评价并非随意进行,它需要多方面的资源,并需要密切注意一些重要环节。以下是我分享给大家一些宝贵的知识&#xf…