从二叉树到B树,全面解析树形数据结构的原理、实现与应用,交互式可视化助你深入理解核心算法
输入层序遍历序列,即可生成并可视化二叉树结构。支持数字、字符串节点,用 null 表示空节点。
二叉树(Binary Tree)是一种层次化的数据结构,每个节点最多有两个子节点:左子节点和右子节点。 它是树结构中最基础且最重要的形式,是许多高级数据结构和算法的基石。
"二叉树是递归定义的:它要么为空树,要么由根节点及其左右两棵互不相交的子二叉树组成。"
根节点:树的顶层节点,无父节点
叶子节点:无子节点的节点
内部节点:至少有一个子节点
深度:从根到该节点的边数
高度:从该节点到最远叶子的边数
• 第 i 层最多有 2i-1 个节点
• 深度为 k 的树最多有 2k-1 个节点
• n 个节点的二叉树有 n+1 个空指针
• 叶子数 = 度为2的节点数 + 1
链式存储:每个节点包含数据域和左右指针,灵活但有指针开销
顺序存储:用数组按层序存储,适合完全二叉树,节点 i 的左子节点为 2i,右子节点为 2i+1
遍历是按某种规则访问树中所有节点的过程,不同遍历方式有不同的应用场景。
访问顺序:根 → 左 → 右
应用:复制树、表达式求值的前缀表示
访问顺序:左 → 根 → 右
应用:BST 有序输出、表达式中缀表示
访问顺序:左 → 右 → 根
应用:删除树、计算目录大小、后缀表达式
访问顺序:逐层从左到右
应用:BFS、计算树宽度、序列化
| 操作 | 普通二叉树 | 二叉搜索树(平均) | BST(最坏) | 平衡BST |
|---|---|---|---|---|
| 查找 | O(n) | O(log n) | O(n) | O(log n) |
| 插入 | O(1)* | O(log n) | O(n) | O(log n) |
| 删除 | O(n) | O(log n) | O(n) | O(log n) |
| 遍历 | O(n) | O(n) | O(n) | O(n) |
* 普通二叉树插入 O(1) 指已知插入位置的情况
不同类型的二叉树针对不同场景进行了优化,理解它们的特点是掌握数据结构的关键。
每一层的节点数都达到最大值,即深度为 k 的满二叉树恰好有 2k-1 个节点。所有叶子节点都在最后一层。
除最后一层外每层都满,且最后一层节点从左到右连续排列。可高效用数组存储,是堆的基础结构。
左子树所有节点 < 根 < 右子树所有节点,递归成立。中序遍历得到有序序列,是动态查找的经典结构。
最早的自平衡BST,严格保证任意节点左右子树高度差不超过1。通过四种旋转操作维持平衡。
弱平衡BST,通过节点着色和5条性质保证最长路径不超过最短路径的2倍。Java TreeMap、C++ map 的底层实现。
每个节点非红即黑;根节点是黑色
叶子(NIL)是黑色;红节点的子节点必为黑
任意节点到其叶子的所有路径包含相同数量的黑节点
完全二叉树 + 堆序性质。大顶堆:父节点 ≥ 子节点;小顶堆:父节点 ≤ 子节点。用于优先队列和堆排序。
利用空指针存储前驱/后继信息,将二叉链表变为双向链表,便于不用栈/队列实现遍历。
带权路径长度最小的二叉树,用于数据压缩。贪心构造:每次选两个最小权值节点合并。
多叉树,用于高效存储和检索字符串集合。每条边代表一个字符,从根到节点的路径表示一个前缀。
用于处理区间查询和更新的平衡二叉树。每个节点存储一个区间的聚合信息(和/最大值/最小值)。
基于二进制思想的数据结构,支持单点更新和前缀查询。实现简单,常数因子小。
B树是一种自平衡的多路搜索树,由 Rudolf Bayer 于1972年发明。它专为减少磁盘I/O而设计, 是数据库索引和文件系统的核心数据结构。
"B树的设计哲学是:宁可让节点更宽(更多键值),也要让树更矮(更少层级),因为磁盘寻道时间远大于顺序读取时间。"
• 每个节点最多有 m 个子节点
• 每个非根节点至少有 ⌈m/2⌉ 个子节点
• 根节点至少有 2 个子节点(非叶时)
• 有 k 个子节点的节点包含 k-1 个键
• 所有叶子节点在同一层
• 节点大小 = 磁盘块大小(通常4KB)
• 一次磁盘I/O读取整个节点
• 树高 = O(logmn),m越大树越矮
• 百万数据只需3-4次磁盘访问
• 内存中二分查找节点内的键
设 n 为键总数,m 为阶数:
• 查找:O(logmn)
• 插入:O(logmn)
• 删除:O(logmn)
• 空间:O(n)
从根开始,在每个节点内二分查找。若找到则返回;否则进入对应子树递归查找,直到叶子节点。
先找到合适的叶子节点插入。若节点满了则分裂:将中间键上提到父节点,左右两半分成两个节点。分裂可能向上传播。
删除比插入复杂。需处理:叶子节点删除、内部节点删除(用前驱/后继替换)、节点合并和借键。
键在叶子节点,直接删除
键在内部节点,用前驱或后继替换后删除
删除后节点键数不足,从兄弟借或与兄弟合并
数据库索引的主流选择。所有数据都在叶子节点,内部节点仅存索引。叶子节点通过链表连接,支持高效范围查询和顺序遍历。
B+树的优化版本。非根节点至少2/3满(而非1/2),分裂前先尝试向兄弟节点转移键,空间利用率更高,分裂频率更低。
支持并发操作的B+树变体。每个节点有指向右兄弟的指针,允许在不锁整棵树的情况下进行并发读写。
MySQL InnoDB、PostgreSQL、Oracle、SQL Server 等主流数据库都使用 B+树 作为默认索引结构。InnoDB 的聚簇索引将数据直接存储在 B+树 叶子节点中。
NTFS(Windows)、HFS+/APFS(macOS)、ext4(Linux)、Btrfs、ZFS 等文件系统使用 B树/B+树 管理文件目录结构和元数据。
LevelDB、RocksDB 使用 LSM树(基于 B树思想)优化写入性能。WiredTiger(MongoDB 默认引擎)使用 B树 作为存储结构。
TiDB、CockroachDB 等分布式数据库使用分布式 B树 管理跨节点数据。etcd、Consul 等配置中心也采用类似结构。
| 维度 | 二叉树/BST | B树 | B+树 |
|---|---|---|---|
| 子节点数 | 最多 2 个 | 最多 m 个 | 最多 m 个 |
| 节点键值数 | 1 个 | 1 ~ m-1 个 | 1 ~ m-1 个 |
| 数据存储位置 | 所有节点 | 所有节点 | 仅叶子节点 |
| 树高度 | O(log₂n) ~ O(n) | O(logmn) | O(logmn) |
| 范围查询 | 需要遍历 | 需要遍历 | 叶子链表高效 |
| 磁盘I/O | 每次1个节点 | 每次1个块 | 每次1个块 |
| 空间利用率 | 指针开销大 | ≥50% | ≥50% |
| 实现复杂度 | 简单 | 中等 | 中等偏复杂 |
| 典型应用 | 内存数据结构 | 文件系统 | 数据库索引 |
• 数据量较小(万级以下)
• 数据完全在内存中
• 需要简单快速实现
• 不涉及磁盘I/O
• 教学或算法练习
• 需要频繁插入删除
• 内存中的有序容器
• 语言标准库(Java TreeMap、C++ map)
• 实时系统(Linux 调度器)
• 需要稳定的最坏情况性能
• 数据量大(百万级以上)
• 数据存储在磁盘
• 需要范围查询
• 数据库/文件系统
• 需要最小化磁盘访问
掌握二叉树的定义、性质、四种遍历方式。实现基本的二叉树操作(创建、遍历、求高度等)。
学习二叉搜索树(BST)的查找、插入、删除。理解BST退化问题,引入平衡的概念。
学习AVL树或红黑树,理解旋转操作和平衡维护。可以选择只深入一种。
理解B树的设计动机(磁盘优化),掌握B树的查找、插入、删除和分裂合并。
学习B+树及其在数据库索引中的应用,理解聚簇索引、覆盖索引等概念。