多路平衡树(BTree)的C++实现
B树是一种多路平衡树,我根据《算法导论》中的算法描述实现了C++版本的BTree。关于BTree的各种属性看这里吧,还有别人的实现版本,看这里。我记得书中并没有给出删除的算法,这个部分我是根据书中的描述自己实现的。完成后自己进行过简单的测试,好像没有什么问题。总共是两个文件BTree.h和Test.cpp,BTree的实现在BTree.h文件中。Test.cpp是测试案例。具体代码如下:
1 #ifndef __BTREE_H__ 2 #define __BTREE_H__ 3 4 #include <iostream> 5 6 typedef struct _tagBTreeNode 7 { 8 int key_count; 9 int* key; 10 _tagBTreeNode** child; 11 bool leaf; 12 }BTreeNode, *PBTreeNode; 13 14 class BTree 15 { 16 public: 17 BTree(); 18 ~BTree(); 19 20 bool Insert(int key); 21 bool Delete(int key); 22 void Display(){Print(root);}; 23 24 private: 25 BTreeNode* Search(PBTreeNode pNode, int key); 26 PBTreeNode AllocateNode(); 27 void SplitChild(PBTreeNode pParent, int index, PBTreeNode pChild); 28 PBTreeNode UnionChild(PBTreeNode pParent, PBTreeNode pCLeft, PBTreeNode pCRight, int index); 29 void InsertNonfull(PBTreeNode pNode, int key); 30 int Max(PBTreeNode pNode); 31 int Min(PBTreeNode pNode); 32 bool DeleteNonHalf(PBTreeNode pNode, int key); 33 void DellocateNode(PBTreeNode pNode); 34 void DeleteTree(PBTreeNode pNode); 35 void Print(PBTreeNode pNode); 36 private: 37 PBTreeNode root; 38 int t;//btree's degree 39 }; 40 41 BTree::BTree() : root(NULL), t(4) 42 { 43 }; 44 45 BTree::~BTree() 46 { 47 DeleteTree(root); 48 delete root; 49 }; 50 51 PBTreeNode BTree::AllocateNode() 52 { 53 PBTreeNode pTemp = new BTreeNode; 54 pTemp->key = new int[2 * t]; 55 pTemp->child = new PBTreeNode[2 * t + 1]; 56 57 for(int i = 0; i < 2 * t ; i++) 58 { 59 pTemp->key[i] = 0; 60 pTemp->child[i] = NULL; 61 } 62 pTemp->child[2 * t] = NULL; 63 64 return pTemp; 65 } 66 67 PBTreeNode BTree::Search(PBTreeNode pNode, int key) 68 { 69 int i = 1; 70 while (i <= pNode->key_count && key > pNode->key[i]) 71 i++; 72 73 if (i < pNode->key_count && key == pNode->key[i]) 74 return pNode->child[i]; 75 76 if (pNode->leaf) 77 return NULL; 78 else 79 return Search(pNode->child[i], key); 80 } 81 82 bool BTree::Insert(int key) 83 { 84 PBTreeNode r = root; 85 if(r == NULL) 86 { 87 r = AllocateNode(); 88 r->leaf = true; 89 r->key_count = 0; 90 91 root = r; 92 } 93 94 if (r !=NULL && r->key_count == (2 * t - 1)) 95 { 96 PBTreeNode s = AllocateNode(); 97 root = s; 98 s->leaf = false; 99 s->key_count = 0; 100 s->child[1] = r; 101 SplitChild(s, 1, r); 102 InsertNonfull(s, key); 103 } 104 else 105 { 106 InsertNonfull(r, key); 107 } 108 109 return true; 110 } 111 112 void BTree::SplitChild(PBTreeNode pParent, int index, PBTreeNode pChild) 113 { 114 PBTreeNode pChildEx = AllocateNode(); 115 pChildEx->leaf = pChild->leaf; 116 pChildEx->key_count = t - 1; 117 118 for(int j = 1; j < t; j++) 119 pChildEx->key[j] = pChild->key[j + t]; 120 121 if(!pChild->leaf) 122 for(int j = 1; j <= t; j++) 123 pChildEx->child[j] = pChild->child[j + t]; 124 125 pChild->key_count = t - 1; 126 127 for(int j = pParent->key_count + 1; j > index; j--) 128 pParent->child[j + 1] = pParent->child[j]; 129 pParent->child[index + 1] = pChildEx; 130 131 for(int j = pParent->key_count; j >= index; j--) 132 pParent->key[j + 1] = pParent->key[j]; 133 pParent->key[index] = pChild->key[t]; 134 pParent->key_count++; 135 } 136 137 void BTree::InsertNonfull(PBTreeNode pNode, int key) 138 { 139 int i = pNode->key_count; 140 141 if(pNode->leaf) 142 { 143 while(i >= 1 && key < pNode->key[i]) 144 { 145 pNode->key[i + 1] = pNode->key[i]; 146 i--; 147 } 148 149 pNode->key[i + 1] = key; 150 pNode->key_count++; 151 } 152 else 153 { 154 while(i >= 1 && key < pNode->key[i]) 155 i--; 156 i++; 157 158 if(pNode->child[i]->key_count == (2 * t - 1)) 159 { 160 SplitChild(pNode, i, pNode->child[i]); 161 162 if(key > pNode->key[i]) 163 i++; 164 } 165 166 InsertNonfull(pNode->child[i], key); 167 } 168 } 169 170 bool BTree::Delete(int key) 171 { 172 return DeleteNonHalf(root, key); 173 } 174 175 bool BTree::DeleteNonHalf(PBTreeNode pNode, int key) 176 { 177 int i = 1; 178 179 while(i <= pNode->key_count && key > pNode->key[i]) 180 i++; 181 182 if(pNode->leaf)//case 1 183 { 184 if(i <= pNode->key_count && key == pNode->key[i]) 185 { 186 for(int j = i; j < pNode->key_count; j++) 187 pNode->key[j] = pNode->key[j + 1]; 188 pNode->key_count--; 189 190 return true; 191 } 192 else 193 { 194 return false;//没有找到要删除的关键字 195 } 196 } 197 198 if (i <= pNode->key_count && key == pNode->key[i])//case 2 199 { 200 if (pNode->child[i]->key_count >= t)//case a 201 { 202 key = Max(pNode->child[i]); 203 pNode->key[i] = key; 204 205 return DeleteNonHalf(pNode->child[i], key); 206 } 207 else if(pNode->child[i + 1]->key_count >= t)//case b 208 { 209 key = Min(pNode->child[i + 1]); 210 pNode->key[i] = key; 211 212 return DeleteNonHalf(pNode->child[i + 1], key); 213 } 214 else//case c 215 { 216 PBTreeNode pChild = UnionChild(pNode, pNode->child[i], pNode->child[i + 1], i); 217 218 return DeleteNonHalf(pChild, key); 219 } 220 } 221 else if(pNode->child[i]->key_count == t - 1)//case 3 222 { 223 if ( i > 1 && pNode->child[i - 1]->key_count >= t)//a_left 224 { 225 PBTreeNode pMidNode = pNode->child[i]; 226 PBTreeNode pPreNode = pNode->child[i - 1]; 227 228 int nPreNodeKeyCount = pPreNode->key_count; 229 230 for (int j = pMidNode->key_count + 1; j > 1; j--) 231 pMidNode->key[j] = pMidNode->key[j - 1]; 232 pMidNode->key[1] = pNode->key[i - 1]; 233 234 for (int j = pMidNode->key_count + 2; j > 1; j--) 235 pMidNode->child[j] = pMidNode->child[j - 1]; 236 pMidNode->child[1] = pPreNode->child[nPreNodeKeyCount + 1]; 237 pMidNode->key_count++; 238 239 pNode->key[i - 1] = pPreNode->key[nPreNodeKeyCount]; 240 241 pPreNode->key[nPreNodeKeyCount] = 0; 242 pPreNode->key[nPreNodeKeyCount + 1] = NULL; 243 pPreNode->key_count--; 244 245 return DeleteNonHalf(pMidNode, key); 246 } 247 else if( i <= pNode->key_count && pNode->child[i + 1]->key_count >= t)//a_right 248 { 249 PBTreeNode pMidNode = pNode->child[i]; 250 PBTreeNode pNextNode = pNode->child[i + 1]; 251 252 int nNextNodeKeyCount = pNextNode->key_count; 253 int nMidNodeKeyCount = pMidNode->key_count; 254 255 pMidNode->key[nMidNodeKeyCount + 1] = pNode->key[i]; 256 pMidNode->child[nMidNodeKeyCount + 2] = pNextNode->child[1]; 257 pMidNode->key_count++; 258 259 pNode->key[i] = pNextNode->key[1]; 260 261 for( int j = 1; j < nNextNodeKeyCount; j++) 262 pNextNode->key[j] = pNextNode->key[j + 1]; 263 for( int j = 1; j <= nNextNodeKeyCount; j++) 264 pNextNode->child[j] = pNextNode->child[j + 1]; 265 pNextNode->key_count--; 266 267 return DeleteNonHalf(pMidNode, key); 268 } 269 else//b 270 { 271 if (i > pNode->key_count)//当i指向最后一个关键字的时候,合并的时候要往前移动一步 272 i--; 273 274 PBTreeNode pChild = UnionChild(pNode, pNode->child[i], pNode->child[i + 1], i); 275 276 return DeleteNonHalf(pChild, key); 277 } 278 } 279 280 return DeleteNonHalf(pNode->child[i], key); 281 } 282 283 PBTreeNode BTree::UnionChild(PBTreeNode pParent, PBTreeNode pCLeft, PBTreeNode pCRight, int index) 284 { 285 for(int i = 1; i < t; i++) 286 pCLeft->key[t + i] = pCRight->key[i]; 287 pCLeft->key[t] = pParent->key[index]; 288 289 for(int i = 1; i <= t; i++) 290 pCLeft->child[t + i] = pCRight->child[i]; 291 pCLeft->key_count = 2 * t - 1; 292 293 for(int i = index; i < pParent->key_count; i++) 294 pParent->key[i] = pParent->key[i + 1]; 295 296 for(int i = index + 1; i <= pParent->key_count; i++) 297 pParent->child[i] = pParent->child[i + 1]; 298 pParent->key_count--; 299 300 DellocateNode(pCRight); 301 302 if (pParent->key_count == 0) 303 { 304 DellocateNode(root); 305 root = pCLeft; 306 } 307 308 return pCLeft; 309 } 310 311 void BTree::DellocateNode(PBTreeNode pNode) 312 { 313 delete[] pNode->key; 314 delete[] pNode->child; 315 delete pNode; 316 } 317 318 int BTree::Max(PBTreeNode pNode) 319 { 320 while (!pNode->leaf) 321 { 322 pNode = pNode->child[pNode->key_count + 1]; 323 } 324 325 return pNode->key[pNode->key_count]; 326 } 327 328 int BTree::Min(PBTreeNode pNode) 329 { 330 while (!pNode->leaf) 331 { 332 pNode = pNode->child[1]; 333 } 334 335 return pNode->key[1]; 336 } 337 338 void BTree::DeleteTree(PBTreeNode pNode)//最后的根元素没有被删除 但是根里的关键字数组和孩子指针数组已经删除 339 { 340 if(pNode->leaf) 341 { 342 delete[] pNode->key; 343 delete[] pNode->child; 344 } 345 else 346 { 347 for(int i = 1; i <= pNode->key_count + 1; i++) 348 { 349 DeleteTree(pNode->child[i]); 350 delete pNode->child[i]; 351 } 352 353 delete[] pNode->key; 354 delete[] pNode->child; 355 } 356 } 357 358 void BTree::Print(PBTreeNode pNode) 359 { 360 if(pNode->leaf) 361 { 362 std::cout << "leaf key_count = " << pNode->key_count << " key list :" ; 363 364 for(int i = 1; i <= pNode->key_count; i++) 365 { 366 //std::cout << " i = " << i << std::endl; 367 std::cout << pNode->key[i] << " , "; 368 } 369 370 std::cout << std::endl; 371 } 372 else 373 { 374 for(int i = 1; i <= pNode->key_count + 1; i++) 375 Print(pNode->child[i]); 376 377 std::cout << "inner node key_count " << pNode->key_count << " key list :" ; 378 379 for(int i = 1; i <= pNode->key_count; i++) 380 { 381 //std::cout << " i = " << i << std::endl; 382 std::cout << pNode->key[i] << " , "; 383 } 384 std::cout << std::endl; 385 } 386 } 387 388 #endif // __BTREE_H__
测试案例代码如下:
1 #include "BTree.h" 2 #include <ctime> 3 #include <iostream> 4 #include <cstdlib> 5 #include <set> 6 7 int main() 8 { 9 BTree b; 10 11 for(int i = 50; i > 1; i--) 12 { 13 int x = rand() % 10000; 14 b.Insert(x); 15 } 16 17 b.Display(); 18 }
编译方式g++ -o Test Test.cpp,执行过程如下:
1 [kiven@localhost Test]$ g++ -o Test Test.cpp 2 [kiven@localhost Test]$ ./Test 3 leaf key_count = 3 key list :27 , 59 , 492 , 4 leaf key_count = 4 key list :886 , 1393 , 1421 , 1530 , 5 leaf key_count = 6 key list :2567 , 2777 , 2862 , 3058 , 3069 , 3135 , 6 leaf key_count = 4 key list :3784 , 3926 , 3929 , 4022 , 7 inner node key_count 3 key list :540 , 2362 , 3426 , 8 leaf key_count = 6 key list :4324 , 4421 , 4919 , 5011 , 5123 , 5198 , 9 leaf key_count = 7 key list :5368 , 5386 , 5736 , 5782 , 6229 , 6429 , 6649 , 10 leaf key_count = 3 key list :7373 , 7763 , 7793 , 11 leaf key_count = 5 key list :8167 , 8315 , 8335 , 8456 , 8537 , 12 leaf key_count = 3 key list :9172 , 9383 , 9802 , 13 inner node key_count 4 key list :5211 , 6915 , 8042 , 8690 , 14 inner node key_count 1 key list :4067 , 15 [kiven@localhost Test]$
完美之道,不在于无可增加,而在于无可减少。