定义
在计算机科学中,B树(英语:B-tree)是一种自平衡的树,能够保持数据有序。这种数据结构能够让查找数据、顺序访问、插入数据及删除的动作,都在对数时间内完成。
为什么要引入B树?
首先,包括前面我们介绍的红黑树是将输入存入内存的一种内部查找树。
而B树是前面平衡树算法的扩展,它支持保存在磁盘或者网络上的符号表进行外部查找,这些文件可能比我们以前考虑的输入要大的多(难以存入内存)。
既然内容保存在磁盘中,那么自然会因为树的深度过大而造成磁盘I/O读写过于频繁(磁盘读写速率是有限制的),进而导致查询效率低下。
那么降低树的深度自然很重要了。因此,我们引入了B树,多路查找树。
特点
树中每个结点最多含有m个孩子(m>=2);
除根结点和叶子结点外,其它每个结点至少有[ceil(m / 2)]个孩子(其中ceil(x)是一个取上限的函数);
若根结点不是叶子结点,则至少有2个孩子(特殊情况:没有孩子的根结点,即根结点为叶子结点,整棵树只有一个根节点);
所有叶子结点都出现在同一层(最底层),叶子结点为外部结点,保存内容,即key和value。
其他结点为内部结点,保存索引,即key和next。
内部结点的关键字key:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
内容结点的指针next:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;
例如:(M=3)
查找和插入
为了方便这里用了一个特殊的哨兵键,它小于其他所有键,用*表示。
一开始B树只含有一个根结点,而根结点在初始化时仅含有该哨兵键。
内部结点中的每个键都与一个结点相关联,以此结点为根的子树种,所有的键都大于等于与此结点关联的键,但小于其他所有键。
这些约定在很大程度上能够简化代码。
代码
点击下载。
该代码实现引入了哨兵键,代码输出则剔除了它。
代码里含有哨兵键的B树(将图片保存到本地查看,字会清晰些):
代码输出的B树(将图片保存到本地查看,字会清晰些):
public class BTree<Key extends Comparable<Key>, Value>
{
// max children per B-tree node = M-1
// (must be even and greater than 2)
private static final int M = 4;
private Node root; // root of the B-tree
private int height; // height of the B-tree
private int n; // number of key-value pairs in the B-tree
// helper B-tree node data type
private static final class Node
{
private int m; // number of children
private Entry[] children = new Entry[M]; // the array of children
// create a node with k children
private Node(int k)
{
m = k;
}
}
// internal nodes: only use key and next
// extern