B树与B+树的原理区别应用

在磁盘存储和内存有序的数据管理中,B 树与 B + 树是核心的数据结构,二者均通过 “多路平衡” 特性减少 IO 次数,但在数据存储方式、查询逻辑上存在本质差异。

一、B 树(Balance Tree):多路平衡搜索树

B 树是 “多路平衡搜索树” 的统称,核心特点是所有节点均可能存储数据,且叶子节点在同一层,保证查询效率稳定。

1. B 树的核心定义(以 m 阶 B 树为例)

“阶(m)” 表示节点最多包含的子节点数,其结构需满足以下规则:

  • 每个节点最多存储 m-1 个关键字(按升序排列),对应 m 个子节点;
  • 根节点:若不是叶子,至少有 2 个子节点(关键字数 ≥1);
  • 非根非叶节点:至少有 ⌈m/2⌉ 个子节点(关键字数 ≥ ⌈m/2⌉ - 1);
  • 所有叶子节点位于同一层,无链表连接。

2. B 树结构图示(以 3 阶 B 树为例)

3 阶 B 树的节点最多含 2 个关键字、3 个子节点,非根节点至少含 1 个关键字、2 个子节点,结构如下:

              [15]                —— 根节点(1个关键字,2个子节点)/        \/          \[5, 10]         [20, 25]     —— 非叶节点(2个关键字,3个子节点)/  |  \         /  |  \/   |   \       /   |   \
[2,3] [7] [12]  [18] [22] [28,30]   —— 叶子节点(存储数据,同层)↑    ↑    ↑     ↑    ↑     ↑数据 数据 数据  数据 数据   数据   —— 所有节点均含数据
  • 查询逻辑如查找 “7”,路径为 15 → 5,10 → 7,找到数据后直接返回(无需到叶子节点);
  • 特点随机查询可能提前终止,但范围查询需回溯父节点(如查 “5-20”,需分别遍历左、中分支,效率低)。

二、B + 树(数据库索引首选)

B + 树是 B 树的 “索引 - 数据分离” 变种,核心特点是仅叶子节点存储完整数据,非叶子节点仅存索引关键字,且叶子节点通过链表连接,专为磁盘 IO 和范围查询优化。

1. B + 树的核心定义(以 m 阶 B + 树为例)

基于 B 树扩展,规则差异如下:

  • 非叶子节点:仅存储 “索引关键字” 和子节点指针,不存实际数据
  • 叶子节点:存储所有关键字及对应数据(或数据地址),按顺序排列,且通过双向链表连接;
  • 所有查询必须到达叶子节点(即使非叶子节点有目标关键字,也需到叶子节点获取数据);
  • 非叶子节点的关键字是叶子节点的 “索引副本”(如非叶节点的 “15”,在叶子节点中也存在)。

2. B + 树结构图示(以 3 阶 B + 树为例)

3 阶 B + 树的非叶节点最多含 2 个索引关键字、3 个子节点,叶子节点含数据并通过链表连接,结构如下:

                 [15, 25]            —— 根节点(仅索引,无数据)/      |      \/       |       \[5, 10]      [20, 25]      [30, 35]   —— 非叶节点(仅索引,无数据)/  |  \       /  |  \       /  |  \/   |   \     /   |   \     /   |   \
[2,3] [7] [12,15] [18,20] [22] [28,30] [32] [36,38]   —— 叶子节点(存数据)↖   ↗   ↖   ↗   ↖   ↗   ↖   ↗   ↖   ↗————————————————————————————————————双向链表(支持范围查询)
  • 查询逻辑如查找 “7”,路径为 15,25 → 5,10 → 7(必须到叶子节点);
  • 范围查询逻辑如查 “5-20”,找到起始叶子节点 “5” 后,沿双向链表遍历至 “20”,无需回溯父节点,效率极高。

三、B 树与 B + 树的构成步骤及图解

1. B 树的构成步骤

B 树是一种自平衡的多路搜索树,构建过程遵循以下步骤:

步骤 1:确定 B 树的阶数

阶数 m 表示一个节点最多能包含的子节点数量,一个 m 阶 B 树的节点最多包含 m-1 个关键字。

以 3 阶 B 树为例(每个节点最多 2 个关键字,3 个子节点):

节点结构:[关键字1, 关键字2]/    |    \子树1  子树2  子树3

在 B 树和 B + 树中,关键字(Key) 是指用于索引和排序的核心数据项,类似于字典中的 “单词”,通过它可以快速定位到对应的数据。

具体来说,关键字有两个核心作用:

  1. 排序依据:同一节点内的关键字按升序排列,形成有序结构
  2. 索引功能:通过关键字可以确定数据的存储位置或子树的范围

举例说明:

假设我们用数字作为关键字构建 B 树,存储学生信息(关键字是学号):

  • 关键字就是具体的学号:5、10、15
  • 节点中的关键字排序后:[5, 10, 15]
  • 每个关键字对应着具体的学生数据(如姓名、成绩等),或指向存储这些数据的子树

在 B + 树中:

  • 非叶节点的关键字:仅作为索引(如[5, 10]),用于定位子树
  • 叶节点的关键字:既作为索引,又关联着实际数据(如[5(张三), 10(李四)]

简单理解:关键字就像图书馆的书号,通过书号(关键字)可以快速找到对应的书籍(数据),而不需要逐个翻阅。

步骤 2:插入关键字并保持排序

新关键字插入到合适的叶子节点,保持节点内关键字有序:

初始插入5:[5]插入3(小于5,放左侧):[3, 5]插入7(大于5,放右侧):[3, 5, 7]  // 此时节点关键字数超过2(3阶B树最大2个),需要分裂

步骤 3:节点分裂(保持平衡)

当节点关键字数超过上限时,中间关键字上移,节点分裂为两个:

分裂[3,5,7]:[5]      // 中间关键字上移为父节点/   \
[3]     [7]  // 分裂为两个子节点

步骤 4:继续插入并调整

插入1、9:[5]/   \
[1,3]   [7,9]插入6(会导致右侧节点分裂):[5,7]/  |  \[1,3] [6] [9]

2. B + 树的构成步骤

B + 树是 B 树的变种,构建过程略有不同:

步骤 1:确定 B + 树的阶数

与 B 树类似,但非叶子节点仅作为索引,不存储实际数据。

以 3 阶 B + 树为例:

非叶节点(仅索引):[关键字1, 关键字2]/    |    \子树1  子树2  子树3叶节点(存数据):[关键字1(数据), 关键字2(数据)]

步骤 2:插入关键字到叶节点

所有关键字都插入到叶节点,保持有序:

插入5、3、7:
叶节点:[3(数据),5(数据),7(数据)]  // 超过上限,需要分裂

步骤 3:叶节点分裂并更新索引

叶节点分裂后,将分裂点关键字添加到父节点作为索引:

分裂后:[5]       // 父节点(仅索引)/   \
[3(数据)] [5(数据),7(数据)]  // 叶节点↖     ↗————链表

步骤 4:继续插入并维护链表

叶节点之间通过链表连接,方便范围查询:

插入1、9、6后:[5,7]/  |  \
[1,3] [5,6] [7,9]↖    ↗   ↖   ↗——————————————双向链表

3. B 树与 B + 树构建对比

构建步骤B 树B + 树
数据存储所有节点都可存储数据仅叶节点存储数据
分裂影响可能影响任何层级节点主要影响叶节点,索引随之更新
链表结构无链表叶节点通过双向链表连接
关键字重复每个关键字只出现一次非叶节点的关键字在叶节点中重复出现

B 树构建更简单,适合随机访问;B + 树构建时需维护额外的链表结构,但更适合范围查询和磁盘存储系统。

四、B 树与 B + 树的核心区别

对比维度B 树B + 树
数据存储位置所有节点(根、非叶、叶子)均存数据仅叶子节点存数据,非叶节点仅存索引
查询路径长度不稳定(可能在非叶节点找到数据)稳定(必须到叶子节点,路径长度固定)
范围查询效率低(需回溯父节点,多次遍历分支)高(叶子节点双向链表,一次遍历)
空间利用率低(非叶节点存数据,单次 IO 加载少)高(非叶节点仅存索引,单次 IO 加载多)
数据一致性差(数据分散存储,更新易导致节点分裂)好(数据集中在叶子,更新影响小)
适用场景内存有序数据、少量数据随机访问磁盘存储(数据库索引、文件系统)

五、B 树与 B + 树在 Java、MySQL 中的应用体现

1. Java 中的应用:B 树变种(红黑树)为主

Java 中无直接的 “标准 B 树” 实现,但核心有序集合依赖红黑树(B 树的 2 阶变种,本质是 “自平衡二叉搜索树”),同时磁盘相关模块隐含 B 树思想。

Java 组件底层结构应用场景与 B 树 / B + 树的关联
TreeMap/TreeSet红黑树(2 阶 B 树变种)- 内存中有序键值对管理,保证O(log n)的增删改查效率;
- 红黑树通过 “平衡” 保证查询稳定,类似 B 树的 “多路平衡” 思想,但仅 2 路分支(适合内存)。
java.nio文件系统B 树(部分实现)- 本地文件系统的索引(如 EXT4)使用 B 树,因文件路径查询多为 “随机访问”,无需频繁范围查询,B 树的提前终止特性更优。

2. MySQL 中的应用:B + 树为绝对核心

MySQL 的索引实现与存储引擎强相关,InnoDB(默认) 和 MyISAM 均基于 B + 树,但数据与索引的关联方式不同,且均弃用 B 树(因范围查询需求高频)。

(1)InnoDB 引擎的 B + 树索引

InnoDB 的核心特性是 “聚簇索引”,即主键索引与数据物理存储绑定,结构如下:

  • 主键索引(聚簇索引)
    • 叶子节点:直接存储完整的行数据(按主键顺序排列);
    • 非叶节点:存储主键值 + 子节点指针(仅索引);
    • 示例(主键为id):
                   顶层非叶节点[10, 20]  /       |       \/        |        \中层非叶节点   中层非叶节点   中层非叶节点[5, 8]      [12, 15]      [25, 30]/  |  \      /  |  \       /  |  \/   |   \    /   |   \     /   |   \叶子节点      叶子节点      叶子节点   ...    叶子节点     叶子节点[id=5, ...]  [id=8, ...]   [id=12, ...] ... [id=25, ...] [id=30, ...]↗      ↖    ↗     ↖    ↗      ↖     ↗         ↖     ↗    ↖   ————————————————————————————————叶子节点通过双向链表连接
  • 非叶节点(顶层、中层):仅存储主键值(如 10、20、5、8 等)和子节点指针,不存储实际行数据,仅用于索引定位
  • 叶子节点:存储完整的行数据(包含所有字段),且严格按照主键值升序排列
  • 双向链表:所有叶子节点通过链表连接,支持高效的范围查询(如WHERE id BETWEEN 5 AND 20

辅助索引(非聚簇索引):

  • 叶子节点:存储 “索引列值 + 主键值”(不存完整数据);
  • 查询逻辑:先查辅助索引得到主键,再通过主键索引查完整数据(称为 “回表”);
  • 示例(索引列为name):
                  顶层非叶节点[Li, Zhang]  /       |       \/        |        \中层非叶节点   中层非叶节点   中层非叶节点[Chen, Han]   [Liu, Wang]   [Zhao, Zhou]/  |  \      /  |  \         /  |  \/   |   \    /   |   \       /   |   \叶子节点  叶子节点  叶子节点  ...  叶子节点  叶子节点
[name=Chen, id=3] [name=Han, id=7] ... [name=Zhao, id=22]↗        ↖    ↗            ↖    ↗             ↖    ————————————————————————————————叶子节点通过双向链表连接
  • 非叶节点:存储索引列值(如 Li、Zhang、Chen 等)和子节点指针,用于索引定位
  • 叶子节点:存储索引列值+主键值(如name=Chen对应id=3),不存储完整行数据
  • 回表查询:通过辅助索引查询时,需先找到对应主键值,再到聚簇索引中查询完整行数据(这就是 "回表")
  • 双向链表:同样支持范围查询(如WHERE name BETWEEN 'Chen' AND 'Wang'

InnoDB 通过这种 B + 树结构实现了索引的高效查询:

  1. 聚簇索引:直接定位完整数据,适合按主键查询
  2. 辅助索引:通过 "索引列→主键→完整数据" 的路径查询,适合按非主键字段过滤
  3. 双向链表:让范围查询无需回溯父节点,大幅提升效率

(2)MyISAM 引擎的 B + 树索引

MyISAM 的索引与数据完全分离(非聚簇索引),结构差异如下:

  • 叶子节点:存储 “索引列值 + 数据行的物理地址”(而非主键);
  • 查询逻辑:通过索引找到物理地址后,直接到磁盘对应位置读取数据(无需回表);
  • 缺点:数据更新可能导致物理地址变化,需同步更新所有索引,效率低于 InnoDB。

(3)MySQL 选择 B + 树的核心原因

  1. 磁盘 IO 效率高非叶节点仅存索引,单次 IO 可加载更多关键字(减少 IO 次数,磁盘 IO 是数据库性能瓶颈);
  2. 范围查询友好叶子节点双向链表支持ORDER BYBETWEEN等操作,无需回溯;
  3. 数据集中存储所有数据在叶子节点,更新时仅需调整叶子节点,一致性更好。

六、总结

  • B 树:适合内存中少量有序数据的随机访问(如 JavaTreeMap的红黑树),但范围查询和磁盘 IO 效率低;
  • B + 树:通过 “索引 - 数据分离” 和 “叶子链表” 优化,成为数据库索引(MySQL InnoDB/MyISAM)、文件系统的首选,完美适配磁盘 IO 和范围查询需求。

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

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

相关文章

从零到一:使用anisble自动化搭建kubernetes集群

在我们云原生俱乐部的暑期学习中,我们了解并学习了需要关于云原生的技术,其中在应用层面上最重要的就是shell编程和ansible,而想要掌握这两项技术离不开的就是实践,而kubernetes是我们云原生技术栈的核心技术,在生产实…

【LangGraph】langgraph.prebuilt.create_react_agent() 函数:快速创建基于 ReAct(Reasoning + Acting)架构的智能代理

本文是对 langgraph.prebuilt.create_react_agent 函数的详细且全面的介绍,涵盖其定义、功能、设计理念、参数、返回值、使用场景、实现原理、示例代码、高级用法、注意事项、与其他方法的对比,以及学习建议。 1. 概述 langgraph.prebuilt.create_react…

北斗导航 | RAIM算法改进方案及性能对比分析报告

github:https://github.com/MichaelBeechan CSDN:https://blog.csdn.net/u011344545 文章目录RAIM算法改进方案及性能对比分析报告一、RAIM算法改进技术框架1.1 多假设分组算法(MHSS)1.2 动态噪声估计算法1.3 多源信息融合技术二、…

数据结构第8章 排序(竟成)

第 8 章 排序【考纲内容】1.排序的基本概念;2. 直接插入排序;3. 折半插入排序;4. 起泡排序(Bubble Sort);5.简单选择排序;6. 希尔排序(Shell Sort);7. 快速排…

【学Python自动化】 5. Python 数据结构学习笔记

一、 列表详解 1 列表方法总结方法描述等价操作rust Vec类似操作list.append(x)末尾添加元素a[len(a):] [x]vec.push(x);list.extend(iterable)扩展列表a[len(a):] iterablevec.extend([4, 5, 6]); 或者更高效:vec.extend_from_slice(&[4, 5, 6]);list.inser…

Python爬虫实战:研究Radar chart,构建多维度数据采集和分析系统

1. 引言 1.1 研究背景与意义 在信息爆炸的时代,互联网蕴含的海量数据已成为企业决策、学术研究和产品评估的重要依据。这些数据往往包含多个维度的特征,如电商平台的商品信息涵盖价格、销量、评价、性能参数等,社交媒体的用户数据涉及活跃度、互动量、内容偏好等。传统的单…

[灵动微电子 MM32BIN560CN MM32SPIN0280]读懂电机MCU之串口DMA

在 MM32SPIN560C 微控制器中,串口(UART)的 DMA 传输可大幅减轻 CPU 负担,实现数据的“自动收发”。结合《MM32SPIN560C 用户手册(中文版)》中 UART 和 DMA 相关章节,以下从“原理匹配”“配置步…

【机器学习】-torch相关知识01

学习代码时遇到的问题,GPT给的答案,如有错误请指出。 问题1 torch.empty nn.init.xavier 问题2 nn.Parameter 是什么? 问题3 self.add_module 问题4 torch.matmul torch.mm 文章目录问题1 torch.empty nn.init.xavier问题2 nn.Parameter 是什…

Hutool DsFactory多数据源切换

一、简单上手&#xff1a;从配置到使用全流程 DsFactory 的核心优势是零侵入配置&#xff0c;支持多种配置方式&#xff0c;不管是 properties 文件还是代码里直接定义&#xff0c;都能快速初始化数据源。先引依赖&#xff08;Maven&#xff09;&#xff1a; <dependency>…

Mysql中事务隔离级别有哪些?

Mysql中事务隔离级别有哪些&#xff1f; 读未提交&#xff1a; 一个事务可以看到另一个事务尚未提交的数据。可能导致脏读。 读已提交&#xff1a; 一个事务只能看到其他事务提交后的数据。避免了脏读&#xff0c;仍可能引发不可重复读。 可重复读&#xff1a; 可以确保一个事务…

el-carousel在新增或者删除el-carousel-item时默认跳到第一页的原因和解决

现象 使用走马灯效果时 当el-carousel-item增加或者减少时&#xff0c;页会跳到第一页 体验很不友好。 原因 当新增或这删除el-carousel-item时&#xff0c;会触发setActiveIndex&#xff08;props.initialindex&#xff09;, setActiveIndex的行为是小于0或者大于最大页会有一…

人工智能学习:机器学习相关面试题(二)

7、有监督学习和无监督学习的区别 有监督学习&#xff1a; 对具有概念标记&#xff08;分类&#xff09;的训练样本进行 学习&#xff0c;以尽可能对训练样本集外的数据进行 标记&#xff08;分类&#xff09;预测。 这里 &#xff0c;所有的标记&#xff08;分类&#xff09…

python如何下载svg图片

# 生成博客文章框架代码 import datetimeblog_content f"""# Python如何下载SVG图片## 引言 SVG&#xff08;可缩放矢量图形&#xff09;作为一种基于XML的矢量图形格式&#xff0c;在Web开发中广泛应用。本文将介绍如何使用Python从网络下载SVG图片&#xff0…

Linux(一) | 初识Linux与目录管理基础命令掌握

个人主页-爱因斯晨 文章专栏-Linux 最近学习人工智能时遇到一个好用的网站分享给大家&#xff1a; 人工智能学习 文章目录个人主页-爱因斯晨文章专栏-Linux一、前言1.为什么学习Linux2.操作系统概述&#xff1a;3.常见的操作系统&#xff1a;二、初识Linux1.诞生2.什么是Linux…

android-studio 安装

下载地址 国内&#xff1a;https://developer.android.google.cn/studio?hlzh-cn 全国&#xff1a;https://developer.android.com/studio 1.设置 ANDROID_HOME 环境变量 ANDROID_HOME D:\zhy\android-studio\sdk 2. 更新 PATH 环境变量 %ANDROID_HOME%\platform-tools %AN…

【重学MySQL】九十三、MySQL字符集与比较规则完全解析

【重学MySQL】九十三、MySQL字符集与比较规则完全解析一、字符集概述1.1 支持的字符集1.2 UTF8与UTF8MB4的区别二、比较规则&#xff08;Collation&#xff09;2.1 比较规则分类2.2 常见比较规则差异三、配置层级与继承关系3.1 配置层级3.2 继承关系四、最佳实践与问题解决4.1 …

基于Kafka的延迟队列

实现原理 通过topic区分不同的延迟时长&#xff0c;每个topic对于一个延迟&#xff0c;比如 topic100 仅存储延迟 100ms 的消息&#xff0c;topic1000 仅存储延迟 1s 的消息&#xff0c;依次类推。生产消息时&#xff0c;消息需按延迟时长投递到对应的topic。消费消息时&#x…

LabVIEW转速仪校准系统

LabVIEW 与机器视觉的智能校准系统以工控机为核心&#xff0c;整合标准源、智能相机等硬件&#xff0c;通过软件实现校准流程自动化&#xff0c;支持 500-6000r/min 转速范围校准&#xff0c;覆盖 5 类转速测量仪&#xff0c;校准时间缩短约 70%&#xff0c;满足计量院高效、精…

Synchronized 概述

1. 初识 synchronized 是 Java 中的关键字&#xff0c;是一种 同步锁 &#xff0c;可重入锁&#xff0c;悲观锁。它修饰的对象有以下几种&#xff1a; 具体表现为以下3种形式。 对于普通同步方法&#xff0c;锁是当前实例对象。 对于静态同步方法&#xff0c;锁是当前类的 Clas…

通过Auth.log来查看VPS服务器是否被扫描和暴力破解及解决办法

说明&#xff1a;很多人vps可能出现过被扫的情况&#xff0c;有的还被爆破了&#xff0c;这里提供下查看方法 查看用密码登陆成功的IP地址及次数grep "Accepted password for root" /var/log/auth.log | awk {print $11} | sort | uniq -c | sort -nr | more查看用密…