我们一直假设我们把数据存在内存中,在内存中数据的读写是十分快的,可是如果数据量太大,我们必须把数据写到磁盘中,可这时候数据的读写可没这么快了,大O模型也不再适用。市面上大多是的外存介质都是机械磁盘,速度主要靠转动磁盘和移动磁头的时间。一个7200RPM的磁盘,每分钟转7200下,一转大约为8.3毫秒,每秒大约能进行120次磁盘访问,可见效率是极其低下的,而处理器每秒能处理5亿个的指令。就算是AVL树,如果数据量上千万,平均成功查找一个数据,大概也要4 、5秒的时间。数据在磁盘中是随机存储的,数据可能分布在不同的区块中,随着深度地增加,访问次数变多,时间变长。所以我们需要减少树的深度。那么B树可以减少树的深度。
B树也是M叉查找树,如下图所示,31个节点的5叉树只有三层,也就是深度只有三,那么最多进行3次磁盘访问。
M阶的B树具有以下特性:
一般我们需要确定M的大小和L的大小,M为每个节点最大 的节点数,L为树叶的最大数据量。我们将每个非叶节点放在一个区块中,所以区块的大小>=(M-1)关键字大小+M每个分支引用的大小。区块大小>=L*每个数据的大小。
下面就是一个5阶的B树。
接着我们来谈一下数据的插入。我们先插入一个57,接着想插入一个55,这时叶子节点已经满了,
所以我们需要分裂叶子,增加父节点的儿子数。
可是加入父节点儿子数满了呢,比如我们现在要插入40,这时候要分裂树叶,可是父节点的儿子数已经满了,这时候就需要向上分裂,如下所示。
当然还有一种方法,可以将多出来的数据交给隔壁有空位置的叶子,同时需要修改关键字。这样的做法可以节省空间。
我们在删除数据项后,如果叶子的数据项量少于L/2,需要和隔壁的叶子合并。