B+树是B树的变形,代码已通过内存泄漏测试和正确性测试。直接给代码吧。
template <int t> class BPlusTree { public: typedef struct _BNode { _BNode(bool _leaf) :n(0), leaf(_leaf), p(NULL) { for (int i = 0; i < 2 * t; i++) c[i] = NULL; } std::pair<int, int> e[2 * t - 1];//e.first是关键字,e.second是数据 _BNode *c[2 * t];//2*t个子节点 bool leaf;//true代表叶子(没有子结点,本身就足以容纳关键数据),false代表结点 int n;//代表关键字个数 _BNode *p;//同一层的结点或子叶 }BNode, *pBNode; BPlusTree(int n) { seed = Seed(log2(n), 4); root = new BNode(true); } void Insert(BNode *x, int k, int d); std::pair<BNode *, int> Search(BNode *x, int k); std::pair<BNode *, int> Prev(BNode *r, int k); std::pair<BNode *, int> Next(BNode *r, int k); void Delete(BNode *x, int k); void Empty(); void Print(BNode *x);//顺序输出 void Print_tree(BNode *x);//层次输出 int Hash(int k); BNode *Root() { return root; } ~BPlusTree() { Empty(); } private: void Split_child(BNode *x, int i, BNode *y); void Insert_directly(BNode *x, int k, int d); int Seed(int n, int iCheck); int _Hash(int k, int w, int p); int seed; BNode *root; };
对应的成员函数
template <int t> void BPlusTree<t>::Insert(typename BPlusTree<t>::BNode *x, int k, int d) { BNode *r = root, *s; if (r->n == 2 * t - 1) { s = new BNode(false); root = s; s->c[0] = r; Split_child(s, 0, r); Insert_directly(s, k, d); } else Insert_directly(r, k, d); } template <int t> typename std::pair<typename BPlusTree<t>::BNode *, int> BPlusTree<t>::Search(typename BPlusTree<t>::BNode *x, int k) {//返回<结点指针,关键字索引> int i = 0; if (x == NULL) return std::make_pair<BNode *, int>(NULL, -1); while (i<x->n && k>x->e[i].first) i++; if (i < x->n && k == x->e[i].first) return std::make_pair(x, i); if (x->leaf) //叶子 return std::make_pair<BNode *, int>(NULL, -1); else return this->Search(x->c[i], k); } template <int t> int BPlusTree<t>::Hash(int k) { return _Hash(k, 32, seed); } template <int t> void BPlusTree<t>::Print(typename BPlusTree<t>::BNode *x) { if (x == NULL) return; for (int i = 0; i < x->n; i++) { if (!x->leaf) Print(x->c[i]); printf("%c-%d%-02s", x->e[i].first, x->e[i].second, " "); } if (!x->leaf) Print(x->c[x->n]); } template <int t> void BPlusTree<t>::Print_tree(typename BPlusTree<t>::BNode *x) { if (x == NULL) return; for (int i = 0; i < x->n; i++) printf("%c-%d%-02s", x->e[i].first, x->e[i].second, " "); if (x->p) printf("from %c\n", x->p->e[0].first); else printf("it is root\n"); if (!x->leaf) //结点 for (int i = 0; i <= x->n; i++) Print_tree(x->c[i]); } template<int t> void BPlusTree<t>::Split_child(typename BPlusTree<t>::BNode *x, int i, typename BPlusTree<t>::BNode *y) {//分裂y,并在x->c[i]处插入y结点 int j; BNode *z = new BNode(y->leaf); if (y->c[t] && Search(y->c[t], y->e[t - 1].first).first) {//右子结点存在一个副本,那么和B树一样的根分裂 z->n = t - 1; for (j = 0; j < t - 1; j++) z->e[j] = y->e[j + t];//复制关键字 if (!y->leaf) //y是结点 for (j = 0; j < t; j++) { z->c[j] = y->c[j + t];//复制子结点 z->c[j]->p = z; } } else {//其余任何情况都是B+树的分裂 //z结点,是x结点的右子结点 z->n = t; for (j = 0; j < t; j++) z->e[j] = y->e[j + t - 1];//复制关键字,保留中间值 if (!y->leaf) //y是结点 for (j = 0; j < t + 1; j++) { z->c[j] = y->c[j + t - 1];//复制子结点,多复制一个 z->c[j]->p = z; } } //y结点,是x结点的左子结点 y->n = t - 1; //在x结点中增加一个子结点z,保证x->n<=2*t-1,并且x结点的i处是y for (j = x->n; j >= i + 1; j--) x->c[j + 1] = x->c[j]; x->c[i + 1] = z; for (j = x->n - 1; j >= i; j--) x->e[j + 1] = x->e[j]; x->e[i].first = y->e[t - 1].first; x->e[i].second = -1; x->n++; //更新父结点信息和下一个结点信息 z->p = y->p = x; } template <int t> void BPlusTree<t>::Insert_directly(typename BPlusTree<t>::BNode *x, int k, int d) { int i = x->n - 1; if (x->leaf) {//同一高度插入关键字k while (i >= 0 && k < x->e[i].first) {//调用此函数前,保证了x->n<2*t-1 x->e[i + 1] = x->e[i]; i--; } x->e[i + 1] = std::make_pair(k, d); x->n++; } else {//结点满了 while (i >= 0 && k < x->e[i].first) i--; i = i + 1; if (x->c[i]->n == 2 * t - 1) { Split_child(x, i, x->c[i]); if (k > x->e[i].first) i++; } Insert_directly(x->c[i], k, d); } } template <int t> typename std::pair<typename BPlusTree<t>::BNode *, int> BPlusTree<t>::Prev(typename BPlusTree<t>::BNode *r, int k) {//返回<结点指针,关键字索引> typename std::pair<BNode *, int> p = this->Search(r, k); BNode *x = p.first, *y; int i = p.second; if (x == NULL) return p; if (x->c[i]) {//左子结点存在,优先查找 x = x->c[i]; while (!x->leaf) x = x->c[x->n]; i = x->n; } else if (i > 0) {//结点内还有比自己小的,次优先查找 } else {//父结点查找 while (x->p) { y = x; x = x->p; for (i = 0; i < x->n + 1; i++) if (x->c[i] == y && i != 0) return std::make_pair(x, i - 1); } if (x == p.first || i == x->n + 1) return std::make_pair<BNode *, int>(NULL, -1); } return std::make_pair(x, i - 1); } template <int t> typename std::pair<typename BPlusTree<t>::BNode *, int> BPlusTree<t>::Next(typename BPlusTree<t>::BNode *r, int k) {//返回<结点指针,关键字索引> typename std::pair<BNode *, int> p = this->Search(r, k); BNode *x = p.first, *y; int i = p.second; if (x == NULL) return p; if (x->c[i + 1]) {//右子结点存在,优先查找 x = x->c[i + 1]; while (!x->leaf) x = x->c[0]; i = 0; } else if (i < x->n - 1) //结点内还有比自己大的,次优先查找 i++; else {//父结点查找 while (x->p) { y = x; x = x->p; for (i = 0; i < x->n + 1; i++) if (x->c[i] == y && i != x->n) return std::make_pair(x, i); } if (x == p.first || i == x->n + 1) return std::make_pair<BNode *, int>(NULL, -1); } return std::make_pair(x, i); } template <int t> void BPlusTree<t>::Delete(typename BPlusTree<t>::BNode *x, int k) { typename std::pair<BNode *, int> p = this->Search(x, k), q; BNode *lSib, *rSib; int i = p.second, j; x = p.first;//x含有目标关键字k if (x == NULL) return; if (x->leaf) {//x是叶子,那么左右兄弟必然也是叶子 //定位左右兄弟lSib, rSib if (x->p) { for (j = 0; j < x->p->n + 1; j++) if (x->p->c[j] == x) break; lSib = (j - 1 > -1) ? x->p->c[j - 1] : NULL; rSib = (j + 1 < x->p->n + 1) ? x->p->c[j + 1] : NULL; } else lSib = rSib = NULL; if (x == root && x->n == 1) { delete x; root = NULL; } else if (x->n >= t) {//case 1,x有至少t个关键字,则直接删除 for (j = i; j < x->n - 1; j++) x->e[j] = x->e[j + 1]; x->n--; } else if (x->n == t - 1) { //case 2a,x仅有t-1个关键字,并且lSib或rSib兄弟右至少t个关键字 if (rSib && rSib->n >= t) {//是右兄弟存在,父结点中对应的关键字是x->p->e[j]->first x->e[x->n] = rSib->e[0];// rSib->e[0]直接覆盖 x->p->e[j].first = rSib->e[1].first;//B+树中是rSib->e[1]关键字覆盖 //x->p没有变化,无需调整,所有变化不影响父结点 x->n++;//x增加一个关键字 for (i = 0; i < rSib->n - 1; i++) rSib->e[i] = rSib->e[i + 1];//删除移走的关键字rSib->e[0] rSib->n--; } else if (lSib && lSib->n >= t) {//是左兄弟存在,父结点中对应的关键字是x->p->e[j-1]->first for (i = 0; i < x->n; i++) x->e[i + 1] = x->e[i]; x->p->e[j - 1].first = lSib->e[lSib->n - 1].first;//左兄弟lSib->e[lSib->n - 1]上升到x->p x->e[0] = lSib->e[lSib->n - 1];//B+树中是lSib->e[lSib->n - 1]覆盖 //x->p同上 x->n++; lSib->n--; } else {//case 2b,此时必定是左或右兄弟都仅有t-1个关键字 if (rSib) {//rSib合并到x if (!rSib->leaf) { if (x->n > 1) { for (j = i; j < x->n - 1; j++) x->e[j] = x->e[j + 1]; x->n--; return; } x->n--;//此时必定是0 for (i = 0; i < rSib->n + 1; i++) { x->c[i] = rSib->c[i];//结点复制,一定要更新父结点 rSib->c[i]->p = x; } x->leaf = false;//此时x不再是叶子 } for (i = 0; i < rSib->n; i++) x->e[x->n + i] = rSib->e[i];//B+树中,此情况不再有父关键字下降到x //调整x->p,保证x->p->c[j]是x for (i = j; i < x->p->n - 1; i++) x->p->e[i] = x->p->e[i + 1]; for (i = j; i < x->p->n; i++) x->p->c[i] = x->p->c[i + 1]; x->p->c[j] = x; x->p->n--; x->n = x->n + rSib->n; delete rSib; } else if (lSib) {//x合并到lSib if (!lSib->leaf) {//站在叶子的角度 if (x->n > 1) { if (i == 0) x->p->e[j - 1].first = x->e[1].first; for (j = i; j < x->n - 1; j++) x->e[j] = x->e[j + 1]; x->n--; return; } x->n--; } else for (i = 0; i < x->n; i++)//同上 lSib->e[lSib->n + i] = x->e[i]; //调整x->p,保证x->p->c[j-1]是lSib for (i = j - 1; i < x->p->n - 1; i++) x->p->e[i] = x->p->e[i + 1]; for (i = j - 1; i < x->p->n; i++) x->p->c[i] = x->p->c[i + 1]; x->p->c[j - 1] = lSib; x->p->n--; lSib->n = lSib->n + x->n; delete x; x = lSib; } if (x->p->n == 0) {//更新父结点 BNode *readyToDel = x->p; if (x->p == root) root = x; if (x->p->p) { for (i = 0; i < x->p->p->n + 1; i++) if (x->p->p->c[i] == x->p) break; x->p->p->c[i] = x; } x->p = x->p->p; delete readyToDel; } } this->Delete(x, k);//递归删除 } } else {//x是内结点 lSib = x->c[i];//左子结点 rSib = x->c[i + 1];//右子结点 if (lSib->n >= t && lSib->n > rSib->n) {//case 3a,左子结点至少有t个关键字 p = this->Prev(root, k);//前驱 q = this->Next(root, k);//一定是本身 if (!p.first->leaf) p = this->Next(p.first, p.first->e[p.second].first);//前驱,叶子 x->e[i].first = p.first->e[p.second].first;//替换掉关键字k q.first->e[q.second] = p.first->e[p.second]; this->Delete(p.first, p.first->e[p.second].first);//递归删除前驱值 } else if (rSib->n >= t) {//case 3b,右子结点至少有t个关键字 p = this->Next(root, k); if (x->c[i+1]->e[0].first!=x->e[i].first && p.first->n==1) x->e[i].first = p.first->p->e[0].first; else x->e[i].first = p.first->e[p.second + 1].first;//B+树中,跳过本身k this->Delete(p.first, p.first->e[p.second].first); } else {//case 3c,此时必定是左或右结点仅有t-1个关键字,直接合并两个结点 if (rSib->leaf && !lSib->leaf) { if (rSib->n > 1) { for (j = 0; j < rSib->n - 1; j++) rSib->e[j] = rSib->e[j + 1]; x->e[i].first = rSib->e[0].first; rSib->n--; return; } } else if (lSib->leaf && !rSib->leaf) {//此时rSib一定不包含关键字k p = this->Next(root, k); if (p.first->n == 1) x->e[i].first = p.first->p->e[0].first; else x->e[i].first = p.first->e[p.second + 1].first; this->Delete(p.first, p.first->e[p.second].first); return; } else if (lSib->leaf && rSib->leaf) { for (j = 0; j < rSib->n; j++) lSib->e[lSib->n + j] = rSib->e[j];//rSib合并到lSib lSib->n = lSib->n + rSib->n; } else { //合并到lSib lSib->e[lSib->n] = x->e[i];//关键字k下降到lSib for (j = 0; j < rSib->n; j++) lSib->e[lSib->n + 1 + j] = rSib->e[j];//rSib合并到lSib for (j = 0; j < rSib->n + 1; j++) { lSib->c[lSib->n + 1 + j] = rSib->c[j]; //调整父结点 rSib->c[j]->p = lSib; } lSib->n = lSib->n + 1 + rSib->n; } //调整x结点,保证x->c[i]是lSib for (j = i; j < x->n - 1; j++) x->e[j] = x->e[j + 1]; for (j = i; j < x->n; j++) x->c[j] = x->c[j + 1]; x->c[i] = lSib; x->n--; delete rSib; if (x->n == 0) {//更新父结点 if (x == root) root = lSib; if (x->p) {//替换x->p-c[?]的子结点 for (j = 0; j < x->p->n + 1; j++) if (x->p->c[j] == x) break; x->p->c[j] = lSib; } lSib->p = x->p; delete x; } this->Delete(lSib, k); } } } template <int t> void BPlusTree<t>::Empty() { while (root && root->n != 0) { printf("%c deleted\n", root->e[0].first); this->Delete(root, root->e[0].first); Print_tree(root); printf("\n"); } } template <int t> int BPlusTree<t>::Seed(int n, int iCheck) { int iStart = n / iCheck, prime = (iStart == 1) ? 2 : iStart; assert(iCheck >= 0 && iCheck <= 8); //odd起始要跳过已经判断了的奇数 for (int j = 0, odd = (iStart % 2 == 0) ? iStart / 2 : (iStart - 1) / 2 + 1; j < 8 - iCheck; odd++) { //生成一个素数 bool fPrime = true; for (int k = 2; k <= sqrt(prime); k++) if (prime % k == 0) { fPrime = false; break; } if (fPrime) //记录素数 j++; prime = odd * 2 + 1;//待判断的奇数 } return prime - 2; } template <int t> int BPlusTree<t>::_Hash(int k, int w, int p) { __int64 s = (sqrt(5) - 1) / 2 * pow(2, w); __int64 r0 = s * k % (__int64)pow(2, w); return r0 / pow(2, w - p);//高p位有效位 } template class BPlusTree<2>;
不明白的,好好复习B树吧。