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 };