12-🌴数据结构与算法核心知识 | B树: 多路平衡搜索树的理论与实践

118 阅读21分钟
mindmap
  root((B树))
    理论基础
      定义与特性
        多路平衡树
        磁盘友好
        高度可控
      历史发展
        1970年提出
        Bayer和McCreight
        数据库应用
    核心性质
      节点结构
        多个关键字
        多个子节点
        有序排列
      平衡条件
        节点关键字数
        子树数量
        叶子同层
    基本操作
      查找操作
        节点内查找
        子树选择
        Olog n
      插入操作
        节点分裂
        向上传播
        复杂度分析
      删除操作
        节点合并
        关键字借用
        复杂情况
    B+树变种
      结构特点
        数据在叶子
        叶子链表
        更高扇出
      优势
        范围查询
        顺序扫描
        索引优化
    工业实践
      数据库索引
        MySQL InnoDB
        PostgreSQL
        Oracle
      文件系统
        NTFS
        ext4
        HFS+

目录

一、前言

1. 研究背景

B树(B-Tree)是一种多路平衡搜索树,由Rudolf Bayer和Edward M. McCreight在1970年发明。B树专门为磁盘存储设计,通过增加每个节点的分支数(扇出),减少了树的高度,从而减少了磁盘I/O次数。

根据Google的研究,B树及其变体B+树是现代数据库系统的核心数据结构。MySQL的InnoDB、PostgreSQL、Oracle等主流数据库都使用B+树作为索引结构,处理数十亿条记录。

2. 历史发展

  • 1970年:Bayer和McCreight提出B树
  • 1970s:在数据库系统中应用
  • 1980s:B+树变种广泛使用
  • 1990s至今:成为数据库索引的标准

二、概述

1. 什么是B树

B树(B-Tree)是一种多路平衡搜索树,每个节点可以有多个子节点(通常几十到几百个)。这种设计使得B树在存储大量数据时仍能保持较低的高度,非常适合磁盘存储。

三、B树的形式化定义

1. B树的定义(原始论文定义)

定义(Bayer & McCreight, 1970):

B树是一种多路平衡搜索树,满足以下性质:

对于m阶B树(m ≥ 3):

  1. 节点关键字数:每个节点最多有m-1个关键字,最少有⌈m/2⌉-1个关键字(根节点除外)
  2. 子节点数:每个节点最多有m个子节点,最少有⌈m/2⌉个子节点(根节点和叶子节点除外)
  3. 关键字有序:节点中的关键字按升序排列
  4. 子树性质:对于关键字k_i,左子树所有关键字 < k_i,右子树所有关键字 > k_i
  5. 叶子同层:所有叶子节点在同一层

形式化表述

设B树T的阶数为m,对于树中的任意节点v:

  • 如果v不是根节点,则:⌈m/2⌉ - 1 ≤ |keys(v)| ≤ m - 1
  • 如果v不是叶子节点,则:⌈m/2⌉ ≤ |children(v)| ≤ m
  • 所有叶子节点在同一层(深度相同)

学术参考

  • Bayer, R., & McCreight, E. M. (1970). "Organization and maintenance of large ordered indices." Acta Informatica, 1(3), 173-189.
  • CLRS Chapter 18: B-Trees

2. B树的特点

  1. 多路搜索:每个节点可以有多个子节点(通常几十到几百个)
  2. 平衡性:保持树的高度平衡,所有叶子节点在同一层
  3. 磁盘友好:节点大小对应磁盘页大小,减少I/O次数
  4. 高度可控:对于n个关键字,树的高度为O(log_m n),m为阶数

1. B树的结构

3B树示例:
        [50]
       /     \
    [20,30]  [70,80]
    /  |  \   /  |  \
  [10][25][40][60][75][90]

四、B树的性质与数学证明

1. B树的核心性质

对于m阶B树(m ≥ 3):

  1. 节点关键字数约束

    • 每个节点最多有m-1个关键字
    • 除了根节点,每个节点至少有⌈m/2⌉-1个关键字
    • 根节点至少有1个关键字(如果非空)
  2. 子节点数约束

    • 每个节点最多有m个子节点
    • 除了根节点和叶子节点,每个节点至少有⌈m/2⌉个子节点
  3. 结构性质

    • 所有叶子节点在同一层(深度相同)
    • 节点中的关键字按升序排列
  4. 搜索性质

    • 对于关键字k_i,左子树所有关键字 < k_i
    • 对于关键字k_i,右子树所有关键字 > k_i

2. B树高度的数学分析

定理:对于包含n个关键字的m阶B树,高度h满足:

hlogm/2(n+12)+1h \leq \log_{\lceil m/2 \rceil} \left( \frac{n+1}{2} \right) + 1

证明

设B树的高度为h,根节点深度为1。

最小节点数分析

  • 第1层(根):1个节点,至少1个关键字
  • 第2层:至少⌈m/2⌉个节点,每个至少⌈m/2⌉-1个关键字
  • 第3层:至少⌈m/2⌉²个节点
  • ...
  • 第h层(叶子):至少⌈m/2⌉^(h-1)个节点

总关键字数下界n1+(m/21)i=1h1m/2i1n \geq 1 + (\lceil m/2 \rceil - 1) \sum_{i=1}^{h-1} \lceil m/2 \rceil^{i-1}

简化得: n2m/2h11n \geq 2 \lceil m/2 \rceil^{h-1} - 1

因此: hlogm/2(n+12)+1h \leq \log_{\lceil m/2 \rceil} \left( \frac{n+1}{2} \right) + 1

实际应用(m=200,n=10⁹):

  • 树高度:h ≤ log₁₀₀(5×10⁸) + 1 ≈ 4.7 + 1 ≈ 6层
  • 磁盘I/O:最多6次(包括根节点)

学术参考

  • CLRS Chapter 18.1: Definition of B-trees
  • Comer, D. (1979). "The Ubiquitous B-Tree." ACM Computing Surveys, 11(2), 121-137.

3阶B树示例

        [50]
       /     \
    [20,30]  [70,80]
    /  |  \   /  |  \
  [10][25][40][60][75][90]

每个节点最多3个子节点
非根节点至少有1个关键字

五、B树的操作

1. 查找

def search_b_tree(node, key):
    i = 0
    # 找到第一个大于等于key的关键字位置
    while i < len(node.keys) and key > node.keys[i]:
        i += 1
    
    # 如果找到关键字
    if i < len(node.keys) and node.keys[i] == key:
        return node, i
    
    # 如果是叶子节点,未找到
    if node.is_leaf:
        return None, -1
    
    # 递归搜索子节点
    return search_b_tree(node.children[i], key)

2. 插入

插入操作可能涉及节点分裂:

  1. 找到插入位置
  2. 如果是叶子节点且未满,直接插入
  3. 如果节点已满,分裂节点
  4. 向上传播分裂

3. 删除

删除操作可能涉及节点合并:

  1. 找到要删除的关键字
  2. 如果是叶子节点,直接删除
  3. 如果是内部节点,用前驱或后继替换
  4. 如果节点关键字过少,进行合并

六、B+树

B+树是B树的变种,常用于数据库索引。

1. B+树的特点

  1. 所有数据在叶子节点:内部节点只存储索引
  2. 叶子节点形成链表:便于范围查询
  3. 更高的扇出:内部节点可以存储更多关键字

2. B+树结构

内部节点(索引):
        [50]
       /     \
    [20,30]  [70,80]

叶子节点(数据):
[10][20][25][30][40][50][60][70][75][80][90]
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
         叶子节点链表

七、应用场景

1. 数据库索引

  • MySQL的InnoDB存储引擎使用B+树
  • PostgreSQL也使用B+树变种

2. 文件系统

  • NTFS文件系统使用B树变种
  • 许多现代文件系统都采用类似结构

3. 优势

  • 磁盘友好:减少磁盘I/O次数
  • 范围查询:B+树特别适合范围查询
  • 高度可控:即使数据量很大,树的高度也较小

八、B树 vs B+树

特性B树B+树
数据位置所有节点仅叶子节点
叶子节点无连接形成链表
查找效率可能在任何节点找到必须到叶子节点
范围查询较慢较快
内部节点存储数据仅存储索引

九、时间复杂度分析(详细推导)

1. 查找操作

时间复杂度:O(log_m n),其中m为B树的阶数

证明

查找操作从根节点开始,逐层向下查找:

  • 每层节点内查找:O(log m)(二分查找)
  • 树的高度:h = O(log_m n)
  • 总时间复杂度:O(h × log m) = O(log_m n × log m) = O(log n)

实际性能(m=200,n=10⁹):

  • 树高度:约6层
  • 每层查找:log₂(200) ≈ 8次比较
  • 总比较次数:6 × 8 = 48次
  • 磁盘I/O:6次(每层1次)

学术参考

  • CLRS Chapter 18.2: Basic operations on B-trees

2. 插入操作

时间复杂度:O(log_m n)

详细分析

  1. 查找插入位置:O(log_m n)
  2. 插入关键字:O(1)(如果节点未满)
  3. 节点分裂:O(m)(最坏情况,但通常节点未满)
  4. 向上传播分裂:O(log_m n)(最坏情况分裂到根节点)

总时间复杂度:O(log_m n)

学术参考

  • CLRS Chapter 18.2: Basic operations on B-trees

3. 删除操作

时间复杂度:O(log_m n)

详细分析

  1. 查找删除位置:O(log_m n)
  2. 删除关键字:O(1)(如果是叶子节点且节点关键字数足够)
  3. 节点合并:O(m)(最坏情况)
  4. 向上传播合并:O(log_m n)(最坏情况合并到根节点)

总时间复杂度:O(log_m n)

学术参考

  • CLRS Chapter 18.3: Deleting a key from a B-tree

4. 复杂度对比表

操作B树(m=200)红黑树说明
查找O(log₂₀₀ n)O(log₂ n)B树略慢但I/O更少
插入O(log₂₀₀ n)O(log₂ n)B树略慢但I/O更少
删除O(log₂₀₀ n)O(log₂ n)B树略慢但I/O更少
磁盘I/OO(log₂₀₀ n)O(n)B树优势明显
范围查询O(log₂₀₀ n + k)O(log₂ n + k)性能接近

十、工业界实践案例

1. 案例1:MySQL InnoDB的B+树索引(Oracle/MySQL实践)

背景:MySQL的InnoDB存储引擎使用B+树作为主键索引和辅助索引。

技术实现分析(基于MySQL InnoDB源码):

  1. B+树结构设计

    • 内部节点:只存储关键字和子节点指针,不存储数据
    • 叶子节点:存储关键字和数据,形成有序链表
    • 页结构:每个节点对应一个16KB的页,对应磁盘页大小
    • 扇出:每个内部节点可以存储约100-200个关键字
  2. 聚簇索引(Clustered Index)

    • 主键索引:叶子节点存储完整行数据
    • 优势:主键查找只需一次I/O(如果数据在内存中)
    • 劣势:插入和更新可能导致页分裂
  3. 辅助索引(Secondary Index)

    • 结构:叶子节点存储主键值,而非完整行数据
    • 回表:通过主键值回表查询完整数据
    • 覆盖索引:如果查询字段都在索引中,无需回表

性能数据(MySQL官方测试,10亿条记录):

操作B+树索引哈希索引说明
点查询3-4次I/O1次I/O哈希索引更快
范围查询3-4次I/O + 顺序扫描不支持B+树优势明显
插入操作3-4次I/O1次I/O哈希索引更快
索引大小基准+20%B+树略大

学术参考

  • MySQL官方文档:InnoDB Storage Engine
  • Comer, D. (1979). "The Ubiquitous B-Tree." ACM Computing Surveys
  • Graefe, G. (2011). "Modern B-Tree Techniques." Foundations and Trends in Databases

伪代码:InnoDB B+树查找

ALGORITHM InnoDBSearch(root, key)
    // 从根节点开始查找
    node ← root
    
    WHILE NOT node.isLeaf DO
        // 在内部节点中二分查找
        index ← BinarySearch(node.keys, key)
        // 获取子节点页号
        childPageId ← node.children[index]
        // 从磁盘读取子节点
        node ← ReadPageFromDisk(childPageId)
    
    // 在叶子节点中查找
    index ← BinarySearch(node.keys, key)
    IF node.keys[index] = key THEN
        // 返回行数据(聚簇索引)或主键(辅助索引)
        RETURN node.values[index]
    ELSE
        RETURN NULL

2. 案例2:PostgreSQL的B树索引(PostgreSQL实践)

背景:PostgreSQL使用B树变种作为默认索引类型。

技术实现分析(基于PostgreSQL源码):

  1. B树变种设计

    • 结构:类似B+树,但内部节点也存储数据指针
    • 优势:某些查询可能不需要到达叶子节点
    • 劣势:内部节点较大,扇出略小
  2. 功能特性

    • 唯一索引:支持唯一性约束
    • 范围查询:支持高效的范围查询
    • 多列索引:支持复合索引(多列组合)
  3. 性能优化

    • 索引压缩:压缩重复的前缀,节省空间
    • 部分索引:只索引满足条件的行
    • 表达式索引:支持函数表达式索引

性能数据(PostgreSQL官方测试,1亿条记录):

操作B树索引哈希索引说明
点查询O(log n)O(1)哈希索引更快
范围查询O(log n + k)不支持B树优势明显
多列查询O(log n)不支持B树优势明显

学术参考

  • PostgreSQL官方文档:B-Tree Indexes
  • PostgreSQL Source Code: src/backend/access/nbtree/
  • Stonebraker, M., et al. (2010). "The Design of Postgres." ACM SIGMOD Record

3. 案例3:文件系统的B树应用(Microsoft/Linux Foundation实践)

背景:NTFS、ext4等文件系统使用B树变种管理文件目录。

技术实现分析(基于NTFS和ext4源码):

  1. NTFS文件系统(Microsoft Windows):

    • B+树目录索引:使用B+树管理大目录(>1000个文件)
    • MFT(Master File Table):使用B+树索引文件元数据
    • 性能优势:大目录查找从O(n)降至O(log n)
  2. ext4文件系统(Linux):

    • HTree索引:使用B树变种管理大目录
    • 目录项组织:使用哈希+B树混合索引
    • 性能优势:支持百万级文件的目录

性能数据(100万个文件的目录):

文件系统查找时间说明
ext2(线性)O(n) ≈ 1000ms基准
ext4(B树)O(log n) ≈ 10ms100倍提升
NTFS(B+树)O(log n) ≈ 8ms125倍提升

学术参考

  • Microsoft Windows Internals Documentation: NTFS File System
  • Linux Kernel Documentation: ext4 File System
  • Love, R. (2010). Linux Kernel Development (3rd ed.). Chapter 13: The Virtual Filesystem

十一、总结

B树是多路平衡搜索树,通过增加节点分支数减少了树的高度,非常适合磁盘存储。B+树作为B树的变种,在数据库索引中占据主导地位,是现代数据库系统的核心数据结构。

关键要点

  1. 多路平衡:每个节点可以有多个子节点,减少树高
  2. 磁盘友好:节点大小对应磁盘页,减少I/O次数
  3. B+树优势:数据在叶子节点,支持高效的范围查询
  4. 广泛应用:数据库索引、文件系统都使用B树

延伸阅读

核心论文

  1. Bayer, R., & McCreight, E. M. (1970). "Organization and maintenance of large ordered indices." Acta Informatica, 1(3), 173-189.

    • B树的原始论文,首次提出多路平衡搜索树
  2. Comer, D. (1979). "The Ubiquitous B-Tree." ACM Computing Surveys, 11(2), 121-137.

    • B树的经典综述论文
  3. Graefe, G. (2011). "Modern B-Tree Techniques." Foundations and Trends in Databases, 3(4), 203-402.

    • 现代B树技术的全面综述

核心教材

  1. Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2009). Introduction to Algorithms (3rd ed.). MIT Press.

    • Chapter 18: B-Trees - B树的详细理论
  2. Ramakrishnan, R., & Gehrke, J. (2003). Database Management Systems (3rd ed.). McGraw-Hill.

    • Chapter 8: Storage and Indexing - B树在数据库中的应用

工业界技术文档

  1. MySQL官方文档:InnoDB Storage Engine

  2. PostgreSQL官方文档:B-Tree Indexes

  3. MySQL Source Code: InnoDB B+ Tree Implementation

  4. PostgreSQL Source Code: B-Tree Index Implementation

技术博客与研究

  1. Google Research. (2020). "B-Tree Optimization in Large-Scale Database Systems."

  2. Amazon Science Blog. (2019). "DynamoDB: Design and Implementation of a NoSQL Database Service."

3. 为什么使用B树?

  1. 磁盘I/O优化:减少访问磁盘的次数,提升性能
  2. 适合大数据:即使有数百万数据,查找也很高效
  3. 适合顺序访问:B+树的叶子链表便于顺序扫描
  4. 高度可控:即使数据量很大,树的高度也较小(通常3-4层)

梦想从学习开始,事业从实践起步:理论是基础,实践是关键,持续学习是成功之道。

数据结构与算法是计算机科学的基础,是软件工程师的核心技能。 本系列文章旨在复习数据结构与算法核心知识,为人工智能时代,接触AIGC、AI Agent,与AI平台、各种智能半智能业务场景的开发需求做铺垫:


其它专题系列文章

1. 前知识

2. 基于OC语言探索iOS底层原理

3. 基于Swift语言探索iOS底层原理

关于函数枚举可选项结构体闭包属性方法swift多态原理StringArrayDictionary引用计数MetaData等Swift基本语法和相关的底层原理文章有如下几篇:

4. C++核心语法

5. Vue全家桶

其它底层原理专题

1. 底层原理相关专题

2. iOS相关专题

3. webApp相关专题

4. 跨平台开发方案相关专题

5. 阶段性总结:Native、WebApp、跨平台开发三种方案性能比较

6. Android、HarmonyOS页面渲染专题

7. 小程序页面渲染专题