B树

B树是一棵多叉树。
性质1:B树的每个节点有若干关键字,比如某一节点的关键字为[4,10,20],则该节点有四个孩子,设为Son[0],Son[1],Son[2],Son[3],满足Son[0]子树的最大值小于等于4,Son[1]子树的最小值大于等于4,Son[1]子树的最大值小于等于10,以此类推。同时,任何节点的关键字以非下降顺序排列。

性质2:另外,B树有一个值MAXD(下面的程序用的MAXD,即最大度),它表示如果一个节点不是根节点,那么它最少要有MAXD个孩子(即最少要有MAXD-1个关键字),最多有2*MAXD个孩子(即最多有2*MAXD-1个关键字);根节点最少有1个关键字,最多有2*MAXD-1个关键字。

 

  1 #include <vector>
  2 
  3 
  4 template<typename Type,int MAXD>
  5 class BTree
  6 {
  7 public:
  8     typedef Type value_type;
  9     typedef value_type* pointer;
 10     typedef value_type& reference;
 11 
 12 private:
 13     struct BtreeNode
 14     {
 15         /***
 16            每个节点最多有2*MAXD个孩子
 17            最多有2*MAXD-1个关键值
 18 
 19            最少有MAXD个孩子,MAXD-1个关键字(根节点除外 根节点允许最少有一个关键值)
 20         **/
 21         BtreeNode *son[MAXD*2];
 22         value_type key[MAXD*2-1];
 23         int n;
 24         bool leaf;
 25 
 26         BtreeNode()
 27         {
 28             memset(son,0,sizeof(son));
 29             n=0;
 30         }
 31 
 32         /**
 33           将key[keyIndex]删掉 同时将删掉son[keyIndex+1]
 34           后面的key以及son向前挪
 35         **/
 36         void deleteKey(const int keyIndex)
 37         {
 38             if(!leaf)
 39             {
 40                 delete son[keyIndex+1];
 41             }
 42 
 43             for(int i=keyIndex;i<n-1;i++)
 44             {
 45                 key[i]=key[i+1];
 46                 if(!leaf)
 47                 {
 48                     son[i+1]=son[i+2];
 49                 }
 50 
 51             }
 52             n--;
 53         }
 54 
 55         /**
 56           将son[childIndex+1]合并到son[childIndex]
 57           合并后当前节点的key[childIndex]将合并到son[childIndex]
 58           导致当前节点关键字个数减少1
 59         **/
 60         void mergeSons(const int childIndex,BtreeNode *&root)
 61         {
 62             BtreeNode* leftNode=son[childIndex];
 63             BtreeNode* rightNode=son[childIndex+1];
 64 
 65             int CurLeftKeyNums=leftNode->n;
 66             leftNode->key[CurLeftKeyNums++]=key[childIndex];
 67             for(int i=0;i<rightNode->n;i++)
 68             {
 69                 leftNode->key[CurLeftKeyNums++]=rightNode->key[i];
 70             }
 71             if(!leftNode->leaf)
 72             {
 73                 for(int i=0;i<=rightNode->n;i++)
 74                 {
 75                     leftNode->son[leftNode->n+1+i]=rightNode->son[i];
 76                 }
 77             }
 78             leftNode->n=CurLeftKeyNums;
 79             deleteKey(childIndex);
 80 
 81             /**
 82               如果当前节点关键字个数为0(这说明当前节点是根节点)
 83               则删除当前节点 同时将当前节点指向仅有的一个孩子节点
 84             **/
 85             if(n==0)
 86             {
 87                 BtreeNode* t=root;
 88                 root=leftNode;
 89                 delete t;
 90             }
 91         }
 92     };
 93 public:
 94     typedef BtreeNode* iterator;
 95 private:
 96 
 97 
 98     BtreeNode *root;
 99 
100 
101     /***
102        查找key
103        若找到 则first指向找到的节点 second为key在对应节点的下标
104        若找不到 first=NULL,second=0
105     **/
106     std::pair<iterator,int> search(BtreeNode* root,const reference key)
107     {
108         if(root==NULL) return std::make_pair((BtreeNode*)0,0);
109         int id=0;
110         while(id<root->n&&root->key[id]<key) id++;
111         if(id<root->n&&key==root->key[id]) return std::make_pair(root,id);
112         else if(root->leaf) return std::make_pair((BtreeNode*)0,0);
113         else return search(root->son[id],key);
114     }
115 
116     BtreeNode* createNode() { return new BtreeNode; }
117 
118 
119     /**
120       x->son[id]有2*MAXD-1个关键字 将其分裂成两个孩子
121       并将中间的关键字提到当前节点
122     **/
123     void splitNode(BtreeNode* x,const int id)
124     {
125         BtreeNode* z=createNode();
126         BtreeNode* y=x->son[id];
127         z->leaf=y->leaf;
128         z->n=MAXD-1;
129         for(int i=0;i<z->n;i++) z->key[i]=y->key[i+MAXD];
130         if(!y->leaf)
131         {
132             for(int i=0;i<MAXD;i++) z->son[i]=y->son[i+MAXD];
133         }
134         y->n=MAXD-1;
135 
136         for(int i=x->n-1;i>=id;i--)
137         {
138             x->key[i+1]=x->key[i];
139             x->son[i+2]=x->son[i+1];
140         }
141         x->key[id]=y->key[MAXD-1];
142         x->son[id+1]=z;
143         x->n++;
144     }
145 
146     /**
147       将key插入到x为根的子树下
148       进入该函数时  x的关键字个数小于2*MAXD-1
149     **/
150     void insertNotFull(BtreeNode* x,const reference key)
151     {
152         int i=x->n-1;
153 
154         /**
155           当前节点是叶节点 直接插入
156         **/
157         if(x->leaf)
158         {
159             while(i>=0&&key<x->key[i])
160             {
161                 x->key[i+1]=x->key[i];
162                 i--;
163             }
164             x->key[i+1]=key;
165             x->n++;
166         }
167         /***
168           当前节点不是叶节点 找到要插入的孩子节点
169         **/
170         else
171         {
172             while(i>=0&&key<x->key[i]) i--;
173             i++;
174             /**
175                孩子节点的关键值已满 则分裂成两个
176             **/
177             if(x->son[i]->n==2*MAXD-1)
178             {
179                 splitNode(x,i);
180                 if(key>x->key[i]) i++;
181             }
182             insertNotFull(x->son[i],key);
183         }
184     }
185 
186     /**
187       得到root的下的最小值
188     **/
189     value_type getSubTreeMinValue(BtreeNode* root)
190     {
191         while(!root->leaf) root=root->son[0];
192         return root->key[0];
193     }
194 
195     /**
196       得到root的下的最大值
197     **/
198     value_type getSubTreeMaxValue(BtreeNode* root)
199     {
200         while(!root->leaf)
201         {
202             root=root->son[root->n];
203         }
204         return root->key[root->n-1];
205     }
206 
207 
208     /**
209      从curNode下删掉key
210      [1] 保证curNode下一定有key
211      [2] 保证如果curNode不是根节点 则curNode关键字个数大于等于MAXD
212           否则curNode的关键字个数大于等于1
213     **/
214     void remove(BtreeNode* &curNode,const reference key)
215     {
216         int keyIndex=-1;
217         for(int i=0;i<curNode->n;i++)
218         {
219             if(curNode->key[i]==key)
220             {
221                 keyIndex=i; break;
222             }
223         }
224         /**
225           key在当前节点且当前节点是叶子 直接删除
226         **/
227         if(-1!=keyIndex&&curNode->leaf)
228         {
229             curNode->deleteKey(keyIndex);
230             /**
231               删掉后当前节点没有关键字了 则置为空(此时curNode为根节点)
232             **/
233             if(curNode->n==0)
234             {
235                 delete curNode;
236                 curNode=NULL;
237             }
238             return;
239         }
240 
241         /**
242           key在当前节点且当前节点不是叶子
243         **/
244         if(-1!=keyIndex)
245         {
246             BtreeNode* processor=curNode->son[keyIndex];
247             BtreeNode* successor=curNode->son[keyIndex+1];
248             /***
249               前面的孩子关键字个数大于等于MAXD 则将前面孩子的最大值代替key
250               然后删除前面孩子最大值
251             **/
252             if(processor->n>=MAXD)
253             {
254                 value_type processorMaxValue=getSubTreeMaxValue(processor);
255                 curNode->key[keyIndex]=processorMaxValue;
256                 remove(processor,processorMaxValue);
257             }
258             /***
259               后面的孩子关键字个数大于等于MAXD 则将后面孩子最小值代替key
260               然后删除后面孩子最小值
261             **/
262             else if(successor->n>=MAXD)
263             {
264                 value_type successorMinValue=getSubTreeMinValue(successor);
265                 curNode->key[keyIndex]=successorMinValue;
266                 remove(successor,successorMinValue);
267             }
268             /***
269               两边的关键字个数都小于MAXD 则将curNode的key和后面孩子都合并到前面的孩子
270               然后在前面的孩子中删掉key
271             **/
272             else
273             {
274                 curNode->mergeSons(keyIndex,curNode);
275                 remove(curNode,key);
276             }
277             return;
278         } //if(-1!=keyIndex)
279 
280         /**
281          key不在当前节点中
282         ***/
283         int childIndex=0;
284         while(childIndex<curNode->n&&key>curNode->key[childIndex]) childIndex++;
285         BtreeNode* deleteNode=curNode->son[childIndex];
286         /**
287           如果key所在节点(deleteNode)的关键字个数大于等于MAXD 直接进行删除
288         **/
289         if(deleteNode->n>=MAXD)
290         {
291             remove(deleteNode,key);
292             return;
293         }
294         /**
295           如果key所在节点(deleteNode)的关键字个数小于MAXD  分三种情况
296         **/
297 
298         /***
299           第一种: 前驱的关键字个数大于等于MAXD  则将curNode的childIndex-1加入到deleteNode最前面
300             将前驱的最大值提到curNode的childIndex-1 同时要移动相应的孩子
301         **/
302         if(childIndex>0&&curNode->son[childIndex-1]->n>=MAXD)
303         {
304             /**
305               deleteNode向后挪动 空出第一个位置(key和son都要移动)
306             **/
307             for(int i=deleteNode->n;i>0;i--)
308             {
309                 deleteNode->key[i]=deleteNode->key[i-1];
310             }
311             for(int i=deleteNode->n+1;i>0;i--)
312             {
313                 deleteNode->son[i]=deleteNode->son[i-1];
314             }
315 
316             BtreeNode* leftNode=curNode->son[childIndex-1];
317 
318             deleteNode->key[0]=curNode->key[childIndex-1];
319             deleteNode->son[0]=leftNode->son[leftNode->n];
320             deleteNode->n++;
321 
322 
323             curNode->key[childIndex-1]=leftNode->key[leftNode->n-1];
324             leftNode->n--;
325             remove(deleteNode,key);
326             return;
327         }
328         /***
329           第二种: 后继的关键字个数大于等于MAXD  则将curNode的childIndex的key加入到deleteNode最后
330             将后继的最小值提到curNode的childIndex 同时要移动相应的孩子
331         **/
332         if(childIndex<curNode->n&&curNode->son[childIndex+1]->n>=MAXD)
333         {
334             BtreeNode* rightNode=curNode->son[childIndex+1];
335 
336             deleteNode->key[deleteNode->n]=curNode->key[childIndex];
337             deleteNode->son[deleteNode->n+1]=rightNode->son[0];
338             deleteNode->n++;
339 
340             curNode->key[childIndex]=rightNode->key[0];
341 
342             /**
343               rightNode删掉第一个 向前挪
344             **/
345             for(int i=0;i<rightNode->n-1;i++)
346             {
347                 rightNode->key[i]=rightNode->key[i+1];
348             }
349             for(int i=0;i<rightNode->n;i++)
350             {
351                 rightNode->son[i]=rightNode->son[i+1];
352             }
353             rightNode->n--;
354             remove(deleteNode,key);
355             return;
356         }
357 
358         /***
359           第三种: 将curNode与左邻居或右邻居合并
360         **/
361         if(childIndex>0)
362         {
363             curNode->mergeSons(childIndex-1,curNode);
364             remove(curNode,key);
365         }
366         else
367         {
368             curNode->mergeSons(childIndex,curNode);
369             remove(curNode,key);
370         }
371     }
372 
373 
374 public:
375 
376     std::pair<iterator,int> search(const reference key)
377     {
378         return search(root,key);
379     }
380 
381     void insert(const reference key)
382     {
383         if(NULL==root)
384         {
385             root=createNode();
386             root->n=1;
387             root->leaf=true;
388             root->key[0]=key;
389             return;
390         }
391 
392         if(root->n==2*MAXD-1)
393         {
394             BtreeNode* r=root;
395             BtreeNode* s=createNode();
396             root=s;
397             s->leaf=false;
398             s->n=0;
399             s->son[0]=r;
400             splitNode(s,0);
401         }
402         insertNotFull(root,key);
403     }
404 
405     void remove(const reference key)
406     {
407         std::pair<iterator,int> searchNode=search(root,key);
408         if(searchNode.first==0) return;
409         remove(root,key);
410     }
411     BTree():root(0) {}
412 };

 

posted @ 2016-10-28 20:57  朝拜明天19891101  阅读(220)  评论(0编辑  收藏  举报