在实际的文件系统中,基本上不使用B_树,而是使用B_树的一种变体,称为m阶B+树。 它与B_树的主要不同是叶子结点中存储记录。在B+树中,所有的非叶子结点可以看成是索引,而其中的关键字是作为“分界关键字”,用来界定某一关键字的记录所在的子树。一棵m阶B+树与m阶B_树的主要差异是:
⑴ 若一个结点有n棵子树,则必含有n个关键字;
⑵ 所有叶子结点中包含了全部记录的关键字信息以及这些关键字记录的指针,而且叶子结点按关键字的大小从小到大顺序链接;
⑶ 所有的非叶子结点可以看成是索引的部分,结点中只含有其子树的根结点中的最大(或最小)关键字。
typedef enum{branch, left} NodeType ;
typedef struct BPNode
{
NodeTag tag ; /* 结点标志 */
int keynum ; /* 结点中关键字的个数 */
struct BTNode *parent ; /* 指向父结点的指针 */
KeyType key[M+1] ; /* 组关键字向量,key[0]未用 */
union pointer
{
struct BTNode *ptr[M+1] ; /* 子树指针向量 */
RecType *recptr[M+1] ; /* recptr[0]未用 */
}ptrType ; /* 用联合体定义子树指针和记录指针 */
}BPNode ;
与B_树相比,对B+树不仅可以从根结点开始按关键字随机查找,而且可以从最小关键字起,按叶子结点的链接顺序进行顺序查找。在B+树上进行随机查找、插入、删除的过程基本上和B_树类似。
在B+树上进行随机查找时,若非叶子结点的关键字等于给定的K值,并不终止,而是继续向下直到叶子结点(只有叶子结点才存储记录) , 即无论查找成功与否,都走了一条从根结点到叶子结点的路径。
B+树的插入仅仅在叶子结点上进行。当叶子结点中的关键字个数大于m时,“分裂”为两个结点,两个结点中所含有的关键字个数分别是ë(m+1)/2û和é (m+1)/2ù ,且将这两个结点中的最大关键字提升到父结点中,用来替代原结点在父结点中所对应的关键字。提升后父结点又可能会分裂,依次类推。