B-树特点以及插入、删除数据过程

news2024/12/22 10:49:44

B树(B-Tree)是一种自平衡的多路查找树,它广泛应用于数据库索引和文件系统中,尤其适用于外部存储设备(如磁盘)。B树的设计使得它能够高效地存储大量数据并支持高效的插入、删除和查询操作。以下是B树的主要特点,详细解释其结构和行为:

特点

1. 多路平衡树

B树是一个多路平衡查找树,不同于传统的二叉树。它的每个节点可以有多个子节点,而不仅限于两个。具体来说,B树的阶数(degree)决定了每个节点的子节点的数量上限。

  • 阶数(m):B树的阶数m是一个重要的参数,表示每个节点最多可以有m个子节点,最多可以存储m-1个键值;父节点最少2个子节点,1一个元素;非父节点最少可以有[m/2]个子节点,[m/2]-1个元素。 注意[m/2]向上取整。
  • 节点结构:每个节点包含多个元素和指向子节点的指针。例如,阶数为m的B树中,一个节点最多包含m-1个键值和m个子节点指针。节点的元素按升序排列,子节点指针在元素之间。
  • 键值:每个节点保存若干个数据项(键),这些键在节点内按升序排列。
  • 指针:每个节点有若干个指针,指向其子节点。一个包含k个键的节点,会有k+1个指针。

2. 平衡性

B树保证了树的平衡性——所有叶子节点都在同一层。这意味着树的高度保持平衡,不会出现偏向某一边的情况,因此,B树能够提供对数时间的查找、插入和删除操作。

  • 高度平衡:从根到任意叶子节点的路径长度相同。这是B树在性能上优于一般二叉树的一个重要特性。因为高度较小,B树的查找效率很高。

3. 有序性

B树的节点内存储的数据是有序的,并且节点之间也保持严格的顺序关系。具体地:

  • 节点内的键值是按升序排列的。
  • 对于节点的每个子节点指针,指向的子树中的键值均满足:
  • 子节点左边的键值小于当前节点的键值。
  • 子节点右边的键值大于当前节点的键值。
  • 这种有序性使得B树能够高效地进行范围查询和逐个访问数据。

4. 每个节点最多存储多个键

B树的每个节点可以存储多个键,这意味着B树的每个节点能够包含大量的数据。这一特点使得B树可以在减少树的高度的同时,增加单次磁盘I/O操作的数据量,从而提高查询效率。

  • 节点的最大容量:在阶数为m的B树中,每个节点最多包含m-1个键。节点的最小容量(也就是每个节点最少存储的键数)为⌈m / 2⌉ - 1个键。
    例如,阶数为3的B树(m=3),每个节点最多存储2个键(即m-1),每个节点至少存储1个键(即⌈m / 2⌉ - 1)。

插入数据

B树的插入操作详解

B树的插入操作用于将一个新的元素插入到树中的适当位置,并确保B树的平衡性。在插入过程中,B树保持自平衡的特性,确保所有叶子节点都在同一层,并且每个节点的键数量不超过规定的最大值,同时不低于最小值。如果插入操作导致节点超出了容量,就会触发节点分裂操作。

插入操作步骤

B树插入操作可以分为几个主要步骤:

  1. 查找插入位置
    首先,进行标准的查找操作,找到待插入元素应插入的位置。插入位置是在叶子节点中,B树通过比较每个节点内的键值确定插入位置。如果目标键值已存在,则不进行插入(具体行为取决于实现方式,有的实现会更新已有元素)。

  2. 在叶子节点插入元素
    一旦找到了适当的插入位置(即叶子节点),并且该叶子节点有足够的空间(即未达到节点的最大容量),我们直接将新的元素插入到该叶子节点中。

  3. 检查是否需要分裂
    如果插入的元素使叶子节点的元素数目超过最大容量(即达到m个键值),则需要进行节点分裂操作。分裂过程的关键是:

    • 将该节点的中间元素移到父节点。
    • 将节点分裂成两个子节点,一个包含左半部分的键,另一个包含右半部分的键。
  4. 递归分裂父节点(如有需要)
    分裂操作会将中间元素推送到父节点。如果父节点也满了(即包含了m-1个键值),则需要递归地对父节点进行分裂,直到找到一个可以容纳新元素的节点。如果根节点也被分裂,则树的高度会增加。

  5. 根节点分裂
    如果根节点发生分裂,树的高度会增加,新的根节点会创建出来,并包含分裂后的两个子节点和一个键值。这样,树的高度增加了一层。

插入操作的详细步骤与图示

以阶数为3的B树为例,假设一个B树的阶数m=3,即每个节点最多可以存储2个元素,最多有3个子节点。初始树如下所示:

        [10]
       /    \
   [5]       [15]

假设我们要插入元素7

  1. 查找插入位置
    从根节点[10]开始,7小于10,因此进入左子树[5]。由于7大于5,插入位置就是[5]节点中。

  2. 插入元素到叶子节点
    将元素7插入到叶子节点[5]中,得到:

    [5, 7]
    
  3. 检查是否需要分裂
    节点[5, 7]包含2个元素,未超过最大容量,因此无需分裂。

插入后的树仍然是平衡的,没有改变结构:

        [10]
       /    \
   [5, 7]    [15]
插入导致节点分裂的情况

假设我们现在要插入元素3,并继续使用阶数m=3的B树。当前树结构为:

        [10]
       /    \
   [5, 7]    [15]
  1. 查找插入位置
    从根节点[10]开始,3小于10,进入左子树[5, 7]。由于3小于5,插入位置就是[5, 7]节点的左边。

  2. 插入元素到叶子节点
    将元素3插入到叶子节点[5, 7],得到:

    [3, 5, 7]
    
  3. 检查是否需要分裂
    节点[3, 5, 7]已经包含3个元素,超过了该节点的最大容量(2个元素)。因此,节点需要分裂。

  4. 节点分裂

    • 将节点[3, 5, 7]分裂为两个节点:
      • 左边节点[3]
      • 右边节点[7]
    • 将中间元素5上移到父节点[10]

分裂后的树结构如下:

        [5, 10]
       /    |    \
   [3]    [5]    [7, 15]

插入操作完成,树的结构发生了改变,原先的叶子节点被分裂,父节点也增加了一个元素。

递归分裂操作

在一些情况下,插入操作可能导致父节点也满了,进而需要递归分裂。假设我们现在有一个阶数为m=3的B树,当前结构如下:

            [20]
           /    \
     [10, 15]    [25, 30]

我们要插入元素17

  1. 查找插入位置
    从根节点[20]开始,17小于20,进入左子树[10, 15]。由于17大于15,插入位置是[10, 15]节点的右边。

  2. 插入元素到叶子节点
    将元素17插入到叶子节点[10, 15]中,得到:

    [10, 15, 17]
    
  3. 检查是否需要分裂
    节点[10, 15, 17]包含3个元素,超过了节点的最大容量(2个元素),因此需要分裂。

  4. 节点分裂

    • 将节点[10, 15, 17]分裂为两个节点:
      • 左边节点[10, 15]
      • 右边节点[17]
    • 将中间元素15上移到父节点[20]

此时,父节点[20]变为[15, 20],树结构变为:

            [15, 20]
           /    |    \
     [10]    [15]    [17, 25, 30]

注意,这里[20]的父节点分裂后增加了新的元素。

总结

B树的插入操作包含以下几个核心步骤:

  1. 查找插入位置:通过树的层级结构,从根节点到叶子节点进行查找,确定插入位置。
  2. 插入元素:如果目标叶子节点有空间,直接插入元素。
  3. 节点分裂:如果插入导致节点超出最大容量,将节点分裂并将中间元素推送到父节点。
  4. 递归分裂:如果父节点也满了,递归地进行分裂,直到找到可以容纳元素的父节点,或者根节点发生分裂,增加树的高度。

在这里插入图片描述

插入操作保证了B树的平衡性,使得查询、插入和删除操作始终保持对数时间复杂度O(log n)。

删除数据

B树的删除操作详解

B树的删除操作不仅需要删除目标元素,还要保证树的平衡性。删除操作可能会导致节点的元素数量低于最小容量,这时需要通过借用合并操作来恢复树的平衡。

B树的删除操作可以分为以下几个步骤:

  1. 查找待删除元素:首先通过标准的查找操作找到要删除的元素。
  2. 删除元素:如果待删除的元素在叶子节点,直接删除;如果在内部节点,则需要借用或合并来处理。
  3. 借用或合并节点:删除元素后,某些节点可能会变得“不满”(即元素数少于最小容量),需要通过借用兄弟节点的元素或将当前节点与兄弟节点合并来维持B树的性质。

具体步骤和情况如下:

B树删除操作的基本步骤

1. 删除叶子节点的元素
  • 如果待删除的元素位于叶子节点,并且该节点中元素的数量大于或等于B树规定的最小数量(即⌈m / 2⌉ - 1个键),可以直接删除该元素。
  • 不需要进行合并或借用,树结构不会发生变化。
2. 删除内部节点的元素

如果待删除的元素位于非叶子节点,情况就更复杂,通常有以下几种处理方式:

  • 替换删除元素:首先,找到待删除元素的前驱或后继元素(通常是该节点左子树的最大元素或右子树的最小元素),并将其替换待删除的元素。然后,删除该前驱或后继元素。这转化为一个在叶子节点删除元素的问题。
  • 删除替代元素并调整:一旦替代元素被删除,我们可以继续执行删除操作,并根据需要调整树的结构。
3. 恢复树的平衡

删除元素后,如果某个节点的元素数小于最小数量(即节点的键数小于⌈m / 2⌉ - 1),则需要恢复树的平衡性。常见的恢复方法包括:

  • 借用操作:从相邻的兄弟节点借用元素。如果兄弟节点有多余的元素,借用一个元素并将其父节点的元素下移。借用后的兄弟节点和当前节点会重新调整,保持平衡。
  • 合并操作:如果相邻的兄弟节点没有多余的元素可借用,则需要将当前节点与兄弟节点合并,合并后的节点元素数会增加,父节点的元素数减少。如果父节点的元素数低于最小数量,则继续向上调整。

删除操作的各种情况

我们通过一个阶数为m = 3的B树来逐步讲解删除操作的不同情况。

示例B树结构

假设当前的B树结构如下(阶数为3,最多可以存储2个元素):

              [30]
             /    \
     [10, 20]      [40, 50]
      /    \        /    \
  [5]      [15]  [35]   [45, 60]

假设我们需要删除元素20

情况一:删除叶子节点的元素
  • 查找位置:元素20位于叶子节点[10, 20]中。
  • 删除:删除20后,节点变为[10],此时该节点的元素数大于或等于最小容量(即1个元素,满足最小容量2个元素的一半),因此无需调整树结构。
              [30]
             /    \
     [10]          [40, 50]
      /    \        /    \
  [5]      [15]  [35]   [45, 60]
情况二:删除内部节点的元素,且使用替代

假设我们需要删除元素30,这个元素位于根节点。

  1. 查找替代元素:为了删除30,我们找到30前驱元素,即其左子树的最大元素20,然后将20替换掉30
  2. 删除替代元素:元素20已经被删除,原来的节点[10, 20]成为[10]
  3. 由于没有发生分裂和合并,树的结构保持不变。

最终树结构变为:

              [20]
             /    \
     [10]          [40, 50]
      /    \        /    \
  [5]      [15]  [35]   [45, 60]
情况三:删除元素导致节点不满,借用兄弟节点的元素

假设我们删除元素15,它位于叶子节点[5, 15]

  1. 查找元素并删除:删除元素15后,节点[5]剩余一个元素,已经少于最小容量(1个元素,最小容量应该是1个元素)。
  2. 借用兄弟节点:我们可以借用右兄弟节点[20]中的元素,将其右边的元素20移动到父节点30中,并将父节点的指针更新。这样,节点[5]会得到补充,变为[5, 10]

树结构如下:

              [30]
             /    \
     [5, 10]       [40, 50]
      /    \        /    \
  [5]      [15]  [35]   [45, 60]
情况四:删除元素导致节点不满,合并操作

假设我们删除元素5,元素5位于[5, 10]

  1. 查找位置并删除:删除5后,节点[10]只剩下1个元素,低于最小容量,需要恢复平衡。
  2. 合并操作:由于右兄弟[15]有元素,可以进行合并。我们将[10][15]合并为一个节点[10, 15]
  3. 更新父节点:父节点[30]中,1015会更新为30,但是由于节点合并没有变化,所以树的结构将被调整。

树结构如下:

              [30]
             /    \
    [10, 15]        [40, 50]
      /    \        /    \
  [5]      [15]  [35]   [45, 60]
总结

B树的删除操作涉及多个复杂的步骤,包括查找、删除、借用、合并等。具体的删除操作可以分为以下几种情况:

  1. 删除叶子节点元素:直接删除元素,不需要额外的操作。
  2. 删除非叶子节点元素:通过替换删除元素为前驱或后继元素,然后删除该元素。
  3. 借用兄弟节点:如果删除元素导致节点元素数量少于最小容量,可以从兄弟节点借用元素来平衡树。
  4. 合并节点:如果借用不可行,节点会与兄弟节点合并,且父节点会相应地调整。

B树的删除操作保证了树的平衡,使得树的高度保持在对数级别,查找、插入和删除操作的时间复杂度都为O(log n)。

在这里插入图片描述

视频参考链接:https://www.bilibili.com/video/BV1JU411d7iY?vd_source=8e9f9cfdea4ecad3b0fa1ad660d5ab18&spm_id_from=333.788.videopod.sections

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

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

相关文章

微信小程序自定义tabbar;禁用某个tab;修改某个tab的样式

微信小程序自定义tabbar;禁用某个tab;修改某个tab的样式 原本使用本身的tabBar就已经很舒服了,很合适了的,但是总有一些脑洞大开的产品和客户,给你搞点多样式,没办法牛马就得去做咯,现在就给大…

操作系统——内存段式和段页式管理

目录 一、为什么要有段式管理? 二、段式管理的实现原理 1、段式虚拟空间 2、段式管理的内存分配与释放 3、段式管理的地址变换 (1)段表 (2)动态地址变换 4、段的共享与保护 (1)共享 &a…

【C#设计模式(10)——装饰器模式(Decorator Pattern)】

前言 装饰器模式可以在运行时为对象添加额外的功,而无需修改原始对象的代码。这种方式比继承更加灵活。 代码 //蛋糕类(抽象类) public abstract class Cake {public abstract void Create(); } //奶油蛋糕类 public class CreamCake : Cak…

千图网 AI 绘画平台——智能图像创作工具

抖知书老师推荐: ​千图网的AI图像处理工具已经上线有一段时间了,随着AI技术的不断提升,越来越多的设计师和创意工作者开始接受并使用这个高效的工具。最初对于AI会影响创作行业的担忧,现在也逐渐消散了。设计师们依然在创造&…

【前端】技术演进发展简史

一、前端 1、概述 1990 年,第一个web浏览器诞生,Tim 以超文本语言 HTML 为基础在 NeXT 电脑上发明了最原始的 Web 浏览器。 1991 年,WWW诞生,这标志着前端技术的开始。 前端(Front-end)和后端(…

【C#设计模式(4)——构建者模式(Builder Pattern)】

前言 C#设计模式(4)——构建者模式(Builder Pattern) 运行结果 代码 public class Computer {private string part1 "CPU";private string part2 "主板";private string part3 "内存";private string part4 "显卡";private st…

android studio导入OpenCv并改造成.kts版本

1.下载opencv Android版本 2.解压导入android studio,我这里是先导入低版本的,还是gradle,直接导入module,我这里是4.2.0的版本 我的as版本是Android Studio Electric Eel 2022.1.1 Patch 2,我导入直接就能用 //load OpenCV engine and init OpenCV library //这里放在oncreat…

【easily-openJCL】要尝试下用 显卡 做数据对称加密吗?

easily-openJCL 要尝试下用 显卡 做数据对称加密吗? 开源技术栏 本文演示了一个案例,使用显卡进行数据加密哦,加密方法是 XOR 目录 文章目录 easily-openJCL 要尝试下用 显卡 做数据对称加密吗?目录开始导入项目库加密操作解密…

挖到宝了!统一dlp数据防泄漏解决方案有哪些?千字长文带你熟知这6款!

信息外泄、内部疏忽、离职泄密、黑客入侵、系统漏洞、第三方风险,这些司空见惯的企业数据泄漏问题,无一不牵动着企业的神经,考验着企业的数据安全防线。 今天,我们就来深挖几款统一dlp数据防泄漏解决方案,帮助企业筑起…

wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器

嗨,大家好,我是小华同学,关注我们获得“最新、最全、最优质”开源项目和高效工作学习方法 wflow-web是一个开源的工作流设计器,它支持可视化拖拽表单组件,动态任意层级结构审批节点,以及复杂流程条件的设置…

VUE3实现好看的世界建筑中国建筑网站源码

文章目录 1.设计来源1.1 网站主界面1.2 登录界面1.3 注册界面1.4 特色建筑展览界面1.5 世界建筑介绍界面1.6 世界建筑介绍 - 详情界面1.7 中国建筑介绍界面1.8 中国建筑介绍 - 详情界面1.9 关于我们界面 2.效果和源码2.1 动态效果2.2 源代码2.3 目录结构 源码下载万套模板&…

Flink新版Source接口源码解析

目录 1. 前言 2. Source解析 2.1 Source类图 2.2 接口和方法说明 2.2.1 Source,> 3. SplitEnumerator解析 3.1 SplitEnumetator类图 3.2 类和方法说明 3.2.1 SplitEnumerator 3.2.2 SimpleVersionedSerializer 4. SourceReader解析 4.1 SourceReader类图 4.2 类…

SpringCloud Gateway网关路由配置 接口统一 登录验证 权限校验 路由属性

介绍 Spring Cloud Gateway 根据请求的路径、HTTP 方法、头部等信息,将请求路由到对应的微服务实例。它支持基于动态路由规则的配置,可以根据请求的 URL、查询参数、请求头等条件,灵活地决定将请求转发到哪个微服务。Spring Cloud Gateway 提…

【老白学 Java】你能想到「封装」说明有点专业

你能想到「封装」说明有点专业 文章来源:《Head First Java》修炼感悟。 上一章,师兄们能否理解对象属性的相互关系? 本章老白想聊聊数据安全的问题,毕竟谁都不想把自己的数据暴露于大庭广众之下。 如果那样的话将毫无隐私可言&a…

chat2db调用ollama实现数据库的操作。

只试了mysql的调用。 其它的我也不用,本来想充钱算了。最后一看单位是美刀。就放弃了这分心。于是折腾了一下。 本地运行chat2db 及chat2db ui https://gitee.com/ooooinfo/Chat2DB clone 后运行起来 chat2db的java端,我现在搞不清这一个项目是有没有…

主机型入侵检测系统(HIDS)——Elkeid在Centos7的保姆级安装部署教程

一、HIDS简介 主机型入侵检测系统(Host-based Intrusion Detection System 简称:HIDS);HIDS作为主机的监视器和分析器,主要是专注于主机系统内部(监视系统全部或部分的动态的行为以及整个系统的状态)。 HIDS使用传统的C/S架构,只需要在监测端安装agent即可,且使用用户…

qt中ctrl+鼠标左键无法进入

现象:qt中ctrl鼠标左键无法跳转部分函数,例如能跳到textEdit->toPlainText().,但无法跳转到toUtf8();但编译没有问题 排查1:我发现是交叉编译链的问题,使用linux自带就可以进,用ATK-I.MX6U就部分不能进…

Android gradle下载失败后 解决方案

Android 导入gradle一直失败,更新gradle源即可 比如项目里默认的是 distributionUrlhttps\://services.gradle.org/distributions/gradle-7.3.3-bin.zip 用下面这个来替换distributionUrlhttps\://mirrors.cloud.tencent.com/gradle/gradle-7.3.3-bin.zip

基于Java Springboot餐厅点餐系统(加入商家版)

一、作品包含 源码数据库设计文档万字全套环境和工具资源部署教程 二、项目技术 前端技术:Html、Css、Js、Vue 数据库:MySQL 后端技术:Java、Spring Boot、MyBatis 三、运行环境 开发工具:IDEA 数据库:MySQL5.7…

开源项目推荐——OpenDroneMap无人机影像数据处理

实景三维作为GIS最火的课题,最近在想做一套自己的三维构建工具,考察了几个开源项目,把自己的搜索过程用csdn记录下来,希望也能帮助到各位同仁。 OpenDroneMap(ODM)是一个开源项目,旨在处理无人…