Skip to content

B+树的数据结构是什么,如何进行查找,为什么不在非叶子节点存入数据

B+树数据结构概述

  • 定义
  • B+树是一种多路平衡查找树,广泛用于数据库和文件系统(如 MySQL InnoDB、MongoDB)中,用于高效存储和检索有序数据。
  • 特点
  • 每个节点可存储多个键(key)和指针,降低树高。
  • 所有数据存储在叶子节点,非叶子节点仅存储索引。
  • 叶子节点通过链表连接,支持范围查询。
  • 优势
  • 高效的查找、插入、删除(O(log n))。
  • 适合磁盘存储,减少 I/O 操作。

核心点

  • B+树的结构优化了范围查询和磁盘访问,非叶子节点不存数据以提高索引效率。

1. B+树数据结构详解

(1) 结构组成

  • 节点类型
  • 根节点:树的入口,可能只有一个键。
  • 内部节点(非叶子节点):存储键和指向子节点的指针,用于导航。
  • 叶子节点:存储实际数据(键值对),通过双向链表连接。
  • 节点属性
  • 阶(order):定义节点的最大子节点数(m阶B+树,节点最多有m个子节点)。
  • 键数量
    • 非叶子节点:最多存储 ( m-1 ) 个键。
    • 叶子节点:最多存储 ( m-1 ) 个键值对。
  • 指针
    • 非叶子节点:指向子节点的指针(最多 ( m ) 个)。
    • 叶子节点:指向前后叶子节点的指针(链表)。
  • 约束
  • 根节点至少 2 个子节点(非叶子时)。
  • 非叶子节点(除根外)键数范围:( \lceil m/2 \rceil - 1 ) 到 ( m-1 )。
  • 叶子节点键数范围:( \lceil m/2 \rceil - 1 ) 到 ( m-1 )。
  • 所有叶子节点在同一层(平衡树)。

(2) 示例(3阶 B+树)

  • 结构
       [17]
      /    \
  [5,13]  [25,31]
  /  |  \  /  |  \
 [1,3][7,11][15][19,23][27,29][33,37]

  • 说明
  • 根节点:键 [17],2 个子节点。
  • 内部节点:如 [5,13],3 个子节点。
  • 叶子节点:如 [1,3],存储数据,链表连接 [1,3] -> [7,11] -> [15] -> ...
  • 存储
  • 键:1, 3, 5, 7, 11, 13, 15, 17, 19, 23, 25, 27, 29, 31, 33, 37。
  • 数据:仅在叶子节点(如 [1,3] 存储键 1 和 3 的记录)。

(3) 与 B 树的区别

  • B+树
  • 数据只存叶子节点,非叶子节点仅存键。
  • 叶子节点链表连接,适合范围查询。
  • 更低的树高(更多键 per 节点)。
  • B 树
  • 所有节点可存数据。
  • 无叶子节点链表,范围查询需遍历。

2. B+树查找过程

(1) 查找步骤

  • 目标:查找键 ( k ) 的记录。
  • 过程
  • 从根开始
    • 比较 ( k ) 与当前节点键。
    • 选择合适的子节点指针(二分查找加速)。
  • 递归向下
    • 若节点是内部节点,继续比较和跳转。
    • 若到达叶子节点,检查是否包含 ( k )。
  • 结果
    • 找到:返回叶子节点的记录。
    • 未找到:返回 null 或失败。
  • 示例(查找键 11):
  • 根节点 [17]:11 < 17,进入左子节点 [5,13]
  • 内部节点 [5,13]:5 < 11 ≤ 13,进入中间子节点 [7,11]
  • 叶子节点 [7,11]:找到 11,返回记录。
  • 时间复杂度
  • O(log n)(n 为键总数)。
  • 树高 ( h \approx \log_m n ),m 为阶,通常很大(100-1000)。
  • 每节点查找:二分查找 ( O(\log m) )。

(2) 范围查询

  • 过程
  • 查找范围起点(如 ( k_1 \leq x \leq k_2 ))。
  • 从叶子节点开始,沿链表遍历直到超出 ( k_2 )。
  • 示例(查找 [7, 15]):
  • 找到 7(在 [7,11])。
  • 沿链表遍历:[7,11] -> [15],返回 7, 11, 15。
  • 效率
  • 查找起点:( O(\log n) )。
  • 遍历范围:( O(k) ),k 为结果数量。

3. 为什么非叶子节点不存数据

(1) 原因

  • 提高索引效率
  • 非叶子节点只存键和指针,占用空间小,单个节点可存更多键(( m-1 ))。
  • 增加节点键数降低树高(( \log_m n )),减少磁盘 I/O。
  • 优化磁盘存储
  • 数据库以 页面(page) 为单位读写(通常 4KB-16KB)。
  • 非叶子节点存储少数据,一个页面可容纳更多键,减少页面加载次数。
  • 支持范围查询
  • 数据集中在叶子节点,链表结构便于顺序遍历。
  • 非叶子节点存数据会导致范围查询复杂(需中序遍历)。
  • 简化维护
  • 数据只在叶子节点,插入/删除只需调整叶子节点,内部节点仅更新键。
  • 降低分裂/合并的复杂性。

(2) 量化分析

  • 假设
  • 页面大小:4KB。
  • 键大小:8 字节。
  • 指针大小:8 字节。
  • 数据记录:128 字节。
  • 非叶子节点(只存键+指针):
  • 每个键+指针:16 字节。
  • 4KB 页面可存:( 4096 / 16 \approx 256 ) 个键。
  • 3 层树可索引:( 256^3 \approx 1.6 ) 亿条记录。
  • 若存数据(键+数据+指针):
  • 每个键+数据+指针:( 8 + 128 + 8 = 144 ) 字节。
  • 4KB 页面仅存:( 4096 / 144 \approx 28 ) 个键。
  • 3 层树索引:( 28^3 \approx 2.2 ) 万条记录。
  • 结论
  • 不存数据使树高更低,索引能力提升约 7000 倍。

(3) 对比 B 树

  • B 树
  • 非叶子节点存数据,增加节点大小,树高更高。
  • 范围查询需遍历子树,效率低于 B+树的链表。
  • B+树
  • 非叶子节点仅存键,树更扁平,I/O 更少。
  • 叶子链表优化范围查询。

4. 面试角度

  • 问“结构”
  • 提根、内部节点、叶子节点,强调链表和平衡。
  • 问“查找”
  • 提二分查找和 O(log n),结合示例。
  • 问“非叶子不存数据”
  • 提降低树高、优化 I/O、支持范围查询。
  • 问“应用”
  • 提 MySQL 索引、文件系统。

5. 总结

B+树是一种多路平衡查找树,根和内部节点存键和指针,叶子节点存数据并通过链表连接。查找通过从根到叶子的二分导航,时间复杂度 O(log n)。非叶子节点不存数据以降低树高、减少 I/O 和优化范围查询,显著提高索引效率。面试可提结构图、查找流程或磁盘优化,清晰展示理解。