自学内容网 自学内容网

B树、B+树

前言

        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. 更新叶子节点的指针,确保链表的连续性。

原文地址:https://blog.csdn.net/oxygen3000/article/details/142548075

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!