本文介绍了B树的定义和基本性质,重点分析了B树的插入、删除操作,然后实现了一个C++版本。仅供网友参考。主要参考书籍《数据结构——用面向对象方法与C++语言描述》(清华大学出版社,殷人昆主编)、《数据结构——C++描述》(清华大学出版社,金元平编著)。
定义:一棵m阶B树是一棵m叉查找树,该树或者为空,或者满足下列性质:(1) 根结点至少有2个子女。(2) 除了根结点和失败结点以外,所有结点至少有[ceil( m/2 )]个子女。(3)树的每个结点最多有m个子女。(4) 所有失败结点都处于同一个层次。
插入操作:B树从空树起,逐个插入关键字而生成。在B树中,每个非失败结点的关键字个数都在[ceil( m/2 )] - 1与m - 1之间。插入时,首先检查树中是否包含要插入的关键字,如果已存在就不再插入。如果不存在,则搜索m阶B树以确定可插入新关键字的叶结点p。如果新关键字的插入使结点p的关键字个数达到m,则需要分裂结点p,否则只要将新的结点p直接插入即可。为了分裂结点,假设插入新关键字后结点p的结构为
m, A0, (K1, A1), (K2,A2), …, (Km, Am),且Ki< Ki+1,1≤ i < m
该结点被分裂为具有如下结构的p和q两个结点:
结点p:[ceil(m/2)]–1, A0, (K1, A1), (K2,A2), …, (K[ceil(m/2)]–1, A[ceil(m/2)]–1)
结点q:m –[ceil(m/2)], A[ceil(m/2)],(K [ceil(m/2)]+1, A [ceil(m/2)]+1), …, (Km, Am)
剩下的关键字K[ceil(m/2)]和新结点指针q构成二元组(K[ceil(m/2)],q),该二元组将被插入到p的双亲结点中。插入双亲又可能分裂之,此过程可能一直向上延伸到根。根结点分裂时,算法将创建一个只含一个关键字的新根结点,从而使整个B树的高度增加1。
删除操作:首先,搜索m阶B树以确定需要删除的关键字x所在结点。如果x在结点z中,x= Ki,且z不是叶结点,则可用子树Ai中的最小关键字或Ai-1中的最大关键字替换x(这两个关键字都位于叶结点中),从而将问题转化为从叶结点中删除关键字。从叶结点p中删除x后有四种情况:
(1)若被删关键字所在叶结点同时又是根结点,如果p至少还有1个关键字,则将其写到磁盘即可。否则,B树变为空。
(2)结点p至少还有[ceil(m/2)]– 1个关键字。这时只要将其写到磁盘即可。
(3)结点p还剩[ceil(m/2)]– 2个关键字,且p的最邻近兄弟y至少有[ceil(m/2)]个关键字。由于p的关键字个数不足,而y的有富余,因而可通过旋转进行调剂,使 p的的关键字个数增加1,y的减少1,从而都满足要求。
(4)结点p还剩[ceil(m/2)] – 2个关键字,而y只有[ceil(m/2)] – 1个关键字。由于p的关键字个数不足,y的也无富余,这时需要将结点p、y和z中的关键字合并成 一个结点。
测试结果:在给出代码之前,先给出测试结果,用了两个测试程序,第一个测试案例比较小,依次插入若干字符,然后依次删除。第二测试程序,随机生成上万个整数执行插入操作,然后随机生成上万整数,执行删除操作。第一个测试程序的插入结果如下图所示。
重构出来为下图,结果是正确的。
第一个测试程序的删除结果为下图所示,最后剩0个结点。
全部源代码:只需包含BTree.h即可,所有实现都在这个头文件中
//测试程序1
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "BTree.h"
using names