B树、B+树

news2024/11/20 14:33:03

前言

        B树和B+树都是平衡的多路搜索树,它们在数据库和文件系统中广泛使用,用于存储和检索数据。B是指balance,也就是平衡的意思。那这俩与平衡二叉树有啥区别?首先要知道AVL树与B树、B+树他们都是自平衡搜索树。

  • ALV的子树间高度不会超过1,通过判断每个节点的平衡因子(左子树的高度减去右子树的高度)来保持平衡,如果任何节点的平衡因子的绝对值超过1,则需要通过旋转(左旋、右旋、双旋)操作来重新平衡树。
  • 而B树、B+树,是多路平衡查找树,每个节点可以有多个子节点,节点可以包含多个键和指向子节点的指针。键将子节点分割成不同的范围,B树通过确保所有叶子节点都在同一层也就是分裂节点和合并节点来保持平衡。

        其实很容易发现,如果在数据库逻辑里面,大量的节点如果用AVL树存储,树的整体高度就会超级高,而B树、B+树是矮胖结构,键越多越胖。所以B树、B+树非常适合用于数据库索引和文件系统的目录结构,因为它们可以减少磁盘I/O操作的次数,迎合磁盘IO的需求,因为磁盘不比内存,访问速度是很慢的,这时候如果使用AVL树,如此高度会大大降低整体性能,此外,AVL树的旋转操作会使逻辑上很近的节点离得很远,这时候就违背了局部性原理(如果一个存储器的某个位置被访问,那么将它附近的位置也会被访问)。到这里我们应该了解了,B树、B+树有个key-value的概念,key用于查找,value用于存储数据。

B树

  • 节点:B树的节点可以包含多个键和指向子节点的指针。每个节点的键值数量可以变化。
  • 平衡:B树通过分裂节点来保持平衡,确保所有叶子节点都在同一层或者相邻叶子节点的层级差不超过1。
  • 搜索:B树支持快速的搜索操作,因为每个节点都保存了键值,可以直接进行比较。
  • 应用:B树常用于文件系统和数据库索引,因为它可以有效地减少磁盘I/O操作。
  • 插入:如果节点未满,直接插入;如果节点已满,进行分裂
  • 删除:找到要删除的键值,如果节点不满,可能需要合并节点。
  • 搜索:从根节点开始,比较键值,沿着指针向下直到找到键值或叶子节点。

        前面我们有讨论到,B树设计是为了满足磁盘使用的要求,就是提高效率,而快速索引恰好需要减少磁盘IO的次数,AVL树的搜索层次在数据量大的时候就肯定会比B树的搜索层次高很多,而每个节点都需要进行磁盘IO,这样看来B+树在这种情况下是力压AVL树的。

B树的分裂和合并是B树维护其平衡性的关键操作。当B树进行插入操作导致某个节点的键值数量超过最大限制时,需要进行分裂;而当删除操作导致节点的键值数量低于最小限制时,可能需要进行合并。

B树的分裂

        分裂操作发生在插入新键值时,如果插入后节点的键值数量超过了节点的最大容量(通常记为M),则需要分裂该节点。

  1. 选择中间键值:选择中间的键值(假设有K个键值,则选择第(M+1)/2个键值,其中M是节点的最大键值容量)。
  2. 分割节点:将中间键值以及其右侧的所有键值移动到新的节点中。
  3. 更新父节点:将中间键值上移至父节点,作为两个子节点的分隔键值。
  4. 处理子节点:新的节点成为原节点的兄弟节点,并且它们共享相同的父节点。

分裂步骤示例

  1. 假设一个节点有键值A, B, C, D, E,最大容量为3,需要插入键值F。
  2. 插入F后,节点变为A, B, C, D, E, F,超过了最大容量。
  3. 选择中间键值C,将C, D, E, F移动到新的节点。
  4. 将C上移至父节点,原节点变为A, B,新节点为D, E, F。

B树的合并

        合并操作发生在删除键值时,如果删除后某个节点的键值数量低于最小限制(通常记为M/2),则需要与兄弟节点合并。

  1. 检查兄弟节点:查看兄弟节点的键值数量。
  2. 借用键值:如果兄弟节点的键值数量大于最小限制,可以从兄弟节点借用一个键值到当前节点。
  3. 合并节点:如果兄弟节点的键值数量等于最小限制,可以将当前节点与一个兄弟节点合并
  4. 更新父节点:如果合并了节点,需要删除父节点中指向当前节点的键值,并调整指针。

合并步骤示例

  1. 假设一个节点有键值A, B,最小容量为2,需要删除键值A。
  2. 删除A后,节点变为B,低于最小容量。
  3. 检查兄弟节点,假设兄弟节点有键值C, D, E。
  4. 如果兄弟节点的键值数量大于最小限制,可以将C借用到当前节点,当前节点变为B, C。
  5. 如果兄弟节点的键值数量等于最小限制,可以将当前节点与兄弟节点合并,合并后的节点为B, C, D。

B+树

  • 节点:B+树的非叶子节点不存储数据,只存储键值和指向子节点的指针。所有的数据都存储在叶子节点中。
  • 平衡:B+树同样保持所有叶子节点在同一层。
  • 链表:B+树的叶子节点之间通过指针连接,形成一个链表,这使得顺序访问非常高效。
  • 搜索:B+树在搜索操作上与B树相似,但由于所有数据都在叶子节点,所以对于范围查询更加高效。
  • 应用:B+树特别适合用于数据库索引和文件系统的存储,因为它可以减少磁盘I/O操作,提高数据读取效率。
  • 插入:首先在叶子节点中插入,如果叶子节点满了,则分裂节点,并且更新父节点。
  • 删除:首先在叶子节点中删除,如果叶子节点不满,可能需要从兄弟节点借键或者合并节点。
  • 搜索:从根节点开始,沿着键值向下直到叶子节点,然后可以在链表中顺序访问。

B+树的合并与分裂操作与B树类似,但有一些关键区别。B+树的特点是所有数据都存储在叶子节点,并且叶子节点之间通过指针连接,形成一个链表。这种结构使得B+树在处理大量数据时更加高效,尤其是在进行范围查询和顺序访问时。

B+树的分裂

分裂操作发生在插入新键值时,如果插入后某个节点的键值数量超过了节点的最大容量(通常记为M),则需要分裂该节点。

  1. 选择中间键值:选择中间的键值(假设有K个键值,则选择第 ⌈(K+1)/2⌉⌈(K+1)/2⌉ 个键值)。
  2. 分割节点:将中间键值以及其右侧的所有键值移动到新的节点中。
  3. 更新父节点:将中间键值上移至父节点,作为两个子节点的分隔键值。
  4. 处理叶子节点:在B+树中,叶子节点之间通过指针连接。分裂操作后,需要更新这些指针以保持链表的连续性。

分裂步骤示例

  1. 假设一个节点有键值A, B, C, D, E,最大容量为3,需要插入键值F。
  2. 插入F后,节点变为A, B, C, D, E, F,超过了最大容量。
  3. 选择中间键值C,将C, D, E, F移动到新的节点。
  4. 将C上移至父节点,原节点变为A, B,新节点为D, E, F。
  5. 更新叶子节点的指针,确保链表的连续性。

B+树的合并

合并操作发生在删除键值时,如果删除后某个节点的键值数量低于最小限制(通常记为M/2),则需要与兄弟节点合并。

  1. 检查兄弟节点:查看兄弟节点的键值数量。
  2. 借用键值:如果兄弟节点的键值数量大于最小限制,可以从兄弟节点借用一个键值到当前节点。
  3. 合并节点:如果兄弟节点的键值数量等于最小限制,可以将当前节点与一个兄弟节点合并。
  4. 更新父节点:如果合并了节点,需要删除父节点中指向当前节点的键值,并调整指针。
  5. 处理叶子节点:在B+树中,叶子节点之间通过指针连接。合并操作后,需要更新这些指针以保持链表的连续性。

合并步骤示例

  1. 假设一个节点有键值A, B,最小容量为2,需要删除键值A。
  2. 删除A后,节点变为B,低于最小容量。
  3. 检查兄弟节点,假设兄弟节点有键值C, D, E。
  4. 如果兄弟节点的键值数量大于最小限制,可以将C借用到当前节点,当前节点变为B, C。
  5. 如果兄弟节点的键值数量等于最小限制,可以将当前节点与兄弟节点合并,合并后的节点为B, C, D。
  6. 更新叶子节点的指针,确保链表的连续性。

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

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

相关文章

知识图谱入门——4:Protégé 5.6.4安装和主要功能介绍、常用插件(2024年10月2日):知识图谱构建的利器

Protg 是斯坦福大学开发的一款开放源代码的本体编辑工具。它为构建、共享和管理本体(Ontologies)提供了一个强大的平台,广泛应用于语义网、知识管理、自然语言处理等领域,特别是知识图谱的开发和管理。Protg 支持 OWL(…

Android-Handle消息传递和线程通信

本文为作者学习笔记,如有误,请各位大佬指点 目录 一、同步异步 二、Java多线程通信 三、Handler是什么 四、Handler相关的类 五、Handler常用方法 1. 发送消息 2. 接收处理消息 3. 切换线程 六、使用Handler 使用Handler更新UI 使用Handler延…

【MAUI】CommunityToolkit社区工具包介绍

一、为什么需要声明式开发 .NET的MVVM,始于WPF,很古典,它甚至可能是现代前端框架“声明式开发”的鼻祖。声明式开发,之所以出现,是因为命令式开发在UI层和代码层上无法解耦的问题。如下图所示: 1、命令式开发:后台代码需要调用UI层的控件(label.Text),如果更新UI层…

植物病虫害检测数据集 7800张 病虫害 带标注 voc yolo 7类

植物病虫害检测数据集 7800张 病虫害 带标注 voc yolo label| pic_ num| box_ num 越橘: . (932,980) 粘虫: (1104, 1104) 稻苞虫: (1389, 2269) 蝗虫: (1198, 1563) 蝽象若虫: (1594, 2576) . 绿蝽象: (1166&#xf…

微服务nginx解析部署使用全流程

目录 1、nginx介绍 1、简介 2、反向代理 3、负载均衡 2、安装nginx 1、下载nginx 2、解压nginx安装包 3、安装nginx​编辑 1、执行configure命令 2、执行make命令 4、启动nginx 1、查找nginx位置并启动 2、常用命令 3、反向代理 1、介绍反向代理配置 1、基础配置…

渗透测试入门学习——编写python脚本实现对网站登录页面的暴力破解

进入靶场输入任意密码进行尝试 发现登陆失败的特征字:“Username and/or password incorrect” 推荐用谷歌浏览器,按F12继续查看请求地址、请求头参数等详细信息,着重关注是否需要Cookie 编写python脚本 import requests # 填入请求地址 u…

Pikachu-csrf-CSRF(POST)

发起请求 拦截抓包&#xff0c;在请求信息中&#xff0c; Engagement Tool --》generate CSRF PoC 得到以下 html 代码 &#xff0c;生成poc.html 文件&#xff0c;当用户点击 <html><!-- CSRF PoC - generated by Burp Suite Professional --><body><…

C++仿函数的介绍以及priority_queue的介绍和模拟实现

目录 1.仿函数 1.1仿函数的介绍 1.2自定义类型使用仿函数 1.3自定义支持比较大小&#xff0c;但是比较的逻辑不是自己想要的逻辑 2.优先级队列priority_queue 2.1priority_queue的介绍 2.2priority_queue的使用 2.3priority_queue的模拟实现 1.仿函数 1.1仿函数的介绍…

Redis中一些其他的数据类型渐进式遍历

我们之前说了redis中的五个类型 分别是&#xff1a;String List Hash Set ZSet&#xff0c;那除了这五个redis文档中还给我们提供了一些其他的数据类型 &#xff08;一&#xff09;一些其他的数据类型 1.stream 这里的数据类型我们只做简单的一些介绍&#xff0c;如果想了解具体…

C++ | Leetcode C++题解之第452题用最少数量的箭引爆气球

题目&#xff1a; 题解&#xff1a; class Solution { public:int findMinArrowShots(vector<vector<int>>& points) {if (points.empty()) {return 0;}sort(points.begin(), points.end(), [](const vector<int>& u, const vector<int>&…

[云] Hands-on with a sample application--DockerCoins 挖矿程序!

DockerCoins 挖矿程序&#xff01;&#x1f4b0;&#x1f433;&#x1f4e6;&#x1f6a2; 不&#xff0c;你不能用 DockerCoins 买咖啡。 DockerCoins 如何工作&#xff1a; 生成一些随机字节&#xff1a; 程序首先生成一串随机的字节数据。这些随机字节用于模拟挖矿过程中的…

Pytorch实现玉米基因表达量预测模型

一、实验要求 通过搭建残差卷积网络&#xff0c;实现对玉米基因表达量的预测 二、实验目的 理解基因表达量预测问题&#xff1a;基因表达预测是生物信息学和基因组学领域中的重要任务之一&#xff0c;促进学科交叉融合。熟悉深度学习框架PyTorch&#xff1a;通过实现基因表达量…

Golang | Leetcode Golang题解之第453题最小操作次数使数组元素相等

题目&#xff1a; 题解&#xff1a; func minMoves(nums []int) (ans int) {min : nums[0]for _, num : range nums[1:] {if num < min {min num}}for _, num : range nums {ans num - min}return }

nodejs --- 使用全球公认头像gravatar

目录 历史&#xff1a;阿凡达 什么是头像&#xff1f; 我为什么要添加 Gravatar&#xff1f; 我怎样才能得到一个Gravatar&#xff1f; 开发者使用 功能描述 安装和使用 实践应用 我们他们名字旁边的灰色图标是怎么出现的。那么这个灰色图标被称为“神秘人”gravatar。…

IT新秀系列:Go语言的兴起

Go语言&#xff08;Golang&#xff09;由谷歌于2007年发起&#xff0c;并于2009年正式开源。它的诞生背景可以追溯到互联网技术的高速发展时期。那时&#xff0c;软件开发面临着多核计算、大规模并发处理、部署和维护效率低下等挑战。作为一种新型的编程语言&#xff0c;Go主要…

Nginx基础详解5(nginx集群、四七层的负载均衡、Jmeter工具的使用、实验验证集群的性能与单节点的性能)

续Nginx基础详解4&#xff08;location模块、nginx跨域问题的解决、nginx防盗链的设计原理及应用、nginx模块化解剖&#xff09;-CSDN博客 目录 14.nginx集群&#xff08;前传&#xff09; 14.1如何理解单节点和集群的概念 14.2单节点和集群的比较 14.3Nginx中的负载均衡…

指纹定位的原理与应用场景

目录 原理 1. 信号特征收集 2. 定位算法 推导公式 距离估算公式 定位算法公式 使用场景 发展前景 指纹定位是一种基于无线信号强度(如Wi-Fi、RFID、蓝牙等)来实现室内定位的技术。它借助于环境中多个基站的信号特征来推断用户的位置。以下是对指纹定位的详细讲解,包…

Spring Boot技术交流平台的设计与实践

3 系统分析 3.1 可行性分析 为了研究问题并确定问题是否能够在最短的时间内以最低的成本解决&#xff0c;经过对该项目的详细调查研究&#xff0c;初步准备了系统的实施报告&#xff0c;面临的问题和解决方案在软件开发方面进行了初步设计和合理安排&#xff0c;确定了开发目标…

Geoserver关于忘记密码的解决方法

第一次安装后&#xff0c;如果你设置密码那一栏一直都是默认的话&#xff0c;那么登录密码应该是账户 admin&#xff0c;密码 geoserver 但是&#xff0c;如果你自己设置了密码和账户&#xff0c;登录又登录不上&#xff0c;或者忘记了&#xff0c;有以下方法可以解决。 本质…

Hive数仓操作(九)

一、Hive的DQL查询顺序 HQL语法基本上与传统的SQL一致&#xff0c;包括SELECT、FROM、WHERE、GROUP BY、HAVING、ORDER BY和LIMIT等关键步骤 SELECT * -- 1. 选择所有列 FROM employees -- 2. 数据来源是 employees 表 WHERE salary > 3000 -- 3. 筛选工资大于 3000 的…