1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
| #include <stdio.h> #include <stdlib.h>
#define OK 1 #define FALSE 0 #define MAXM 10 //定义B树的最大的阶数
const int m=3; //设定B树的阶数 const int Max=m-1; //结点的最大关键字数量 const int Min=(m-1)/2; //结点的最小关键字数量
typedef int KeyType; //KeyType为关键字类型
typedef struct node{ //B树存储结构 int keynum; //结点关键字个数 KeyType key[m+1]; //关键字数组,key[0]未使用 struct node *parent; //双亲结点指针 struct node *ptr[m+1]; //孩子结点指针数组 }BTNode,*BTree;
typedef struct{ BTNode *pt; //指向找到的结点 int i; //在结点中的关键字位置; int tag; //查找成功与否标志 }Result;
int InitBTree(BTree &t){ //初始化B树 t=NULL; return OK; }
int SearchBTNode(BTree p,KeyType k){ //在结点p中查找关键字k的插入位置i int i=0; for(i=0;i<p->keynum&&p->key[i+1]<=k;i++); return i; }
/* 在树t上查找关键字k,返回结果(pt,i,tag)。 若查找成功,则特征值tag=1,关键字k是指针pt所指结点中第i个关键字 否则特征值tag=0,关键字k的插入位置为pt结点的第i个 */ Result SearchBTree(BTree t,KeyType k){
BTree p=t,q=NULL; //初始化结点p和结点q,p指向待查结点,q指向p的双亲 int found=FALSE; //设定查找成功与否标志 int i=0; Result r; //设定返回的查找结果
while(p&&!found){ i=SearchBTNode(p,k); //在结点p中查找关键字k,使得p->key[i]<=k<p->key[i+1] if(i>0&&p->key[i]==k) //找到待查关键字 found=OK; //查找成功 else{ //查找失败 q=p; p=p->ptr[i]; } }
if(found){ //查找成功 r.pt=p; r.i=i; r.tag=1; } else{ //查找失败 r.pt=q; r.i=i; r.tag=0; } return r; //返回关键字k的位置(或插入位置) }
void InsertBTNode(BTree &p,int i,KeyType k,BTree q){ //将关键字k和结点q分别插入到p->key[i+1]和p->ptr[i+1]中 int j; for(j=p->keynum;j>i;j--){ //整体后移空出一个位置 p->key[j+1]=p->key[j]; p->ptr[j+1]=p->ptr[j]; } p->key[i+1]=k; p->ptr[i+1]=q; if(q!=NULL) q->parent=p; p->keynum++; }
void SplitBTNode(BTree &p,BTree &q){ //将结点p分裂成两个结点,前一半保留,后一半移入结点q int i; int s=(m+1)/2; q=(BTNode *)malloc(sizeof(BTNode)); //给结点q分配空间
q->ptr[0]=p->ptr[s]; //后一半移入结点q for(i=s+1;i<=m;i++){ q->key[i-s]=p->key[i]; q->ptr[i-s]=p->ptr[i]; } q->keynum=p->keynum-s; q->parent=p->parent; for(i=0;i<=p->keynum-s;i++) //修改双亲指针 if(q->ptr[i]!=NULL) q->ptr[i]->parent=q; p->keynum=s-1; //结点p的前一半保留,修改结点p的keynum }
void NewRoot(BTree &t,KeyType k,BTree p,BTree q){ //生成新的根结点t,原p和q为子树指针 t=(BTNode *)malloc(sizeof(BTNode)); //分配空间 t->keynum=1; t->ptr[0]=p; t->ptr[1]=q; t->key[1]=k; if(p!=NULL) //调整结点p和结点q的双亲指针 p->parent=t; if(q!=NULL) q->parent=t; t->parent=NULL; }
/* 在树t上结点q的key[i]与key[i+1]之间插入关键字k。 若引起结点过大,则沿双亲链进行必要的结点分裂调整 使t仍是B树 */ void InsertBTree(BTree &t,int i,KeyType k,BTree p){ BTNode *q; int finished,newroot_tag,s; //设定需要新结点标志和插入完成标志 KeyType x; if(p==NULL) //t是空树 NewRoot(t,k,NULL,NULL); //生成仅含关键字k的根结点t else{ x=k; q=NULL; finished=FALSE; newroot_tag=FALSE; while(!finished&&!newroot_tag){ InsertBTNode(p,i,x,q); //将关键字x和结点q分别插入到p->key[i+1]和p->ptr[i+1] if (p->keynum<=Max) finished=OK; //插入完成 else{ s=(m+1)/2; SplitBTNode(p,q); //分裂结点 x=p->key[s]; if(p->parent){ //查找x的插入位置 p=p->parent; i=SearchBTNode(p, x); } else //没找到x,需要新结点 newroot_tag=OK; } } if(newroot_tag==OK) //根结点已分裂为结点p和q NewRoot(t,x,p,q); //生成新根结点t,p和q为子树指针 } }
void Remove(BTree p,int i){ //从p结点删除key[i]和它的孩子指针ptr[i]
int j; for(j=i+1;j<=p->keynum;j++){ //前移删除key[i]和ptr[i] p->key[j-1]=p->key[j]; p->ptr[j-1]=p->ptr[j]; } p->keynum--; }
void Substitution(BTree p,int i){ //查找被删关键字p->key[i](在非叶子结点中)的替代叶子结点(右子树中值最小的关键字) BTNode *q; for(q=p->ptr[i];q->ptr[0]!=NULL;q=q->ptr[0]); p->key[i]=q->key[1]; //复制关键字值 }
void MoveRight(BTree p,int i){ /*将双亲结点p中的最后一个关键字移入右结点q中 将左结点aq中的最后一个关键字移入双亲结点p中*/ int j; BTNode *q=p->ptr[i]; BTNode *aq=p->ptr[i-1];
for(j=q->keynum;j>0;j--){ //将右兄弟q中所有关键字向后移动一位 q->key[j+1]=q->key[j]; q->ptr[j+1]=q->ptr[j]; }
q->ptr[1]=q->ptr[0]; //从双亲结点p移动关键字到右兄弟q中 q->key[1]=p->key[i]; q->keynum++;
p->key[i]=aq->key[aq->keynum]; //将左兄弟aq中最后一个关键字移动到双亲结点p中 p->ptr[i]->ptr[0]=aq->ptr[aq->keynum]; aq->keynum--; }
void MoveLeft(BTree p,int i){ /*将双亲结点p中的第一个关键字移入左结点aq中, 将右结点q中的第一个关键字移入双亲结点p中*/ int j; BTNode *aq=p->ptr[i-1]; BTNode *q=p->ptr[i];
aq->keynum++; //把双亲结点p中的关键字移动到左兄弟aq中 aq->key[aq->keynum]=p->key[i]; aq->ptr[aq->keynum]=p->ptr[i]->ptr[0];
p->key[i]=q->key[1]; //把右兄弟q中的关键字移动到双亲节点p中 q->ptr[0]=q->ptr[1]; q->keynum--;
for(j=1;j<=aq->keynum;j++){ //将右兄弟q中所有关键字向前移动一位 aq->key[j]=aq->key[j+1]; aq->ptr[j]=aq->ptr[j+1]; } }
void Combine(BTree p,int i){ /*将双亲结点p、右结点q合并入左结点aq, 并调整双亲结点p中的剩余关键字的位置*/ int j; BTNode *q=p->ptr[i]; BTNode *aq=p->ptr[i-1];
aq->keynum++; //将双亲结点的关键字p->key[i]插入到左结点aq aq->key[aq->keynum]=p->key[i]; aq->ptr[aq->keynum]=q->ptr[0];
for(j=1;j<=q->keynum;j++){ //将右结点q中的所有关键字插入到左结点aq aq->keynum++; aq->key[aq->keynum]=q->key[j]; aq->ptr[aq->keynum]=q->ptr[j]; }
for(j=i;j<p->keynum;j++){ //将双亲结点p中的p->key[i]后的所有关键字向前移动一位 p->key[j]=p->key[j+1]; p->ptr[j]=p->ptr[j+1]; } p->keynum--; //修改双亲结点p的keynum值 free(q); //释放空右结点q的空间 }
void AdjustBTree(BTree p,int i){ //删除结点p中的第i个关键字后,调整B树 if(i==0) //删除的是最左边关键字 if(p->ptr[1]->keynum>Min) //右结点可以借 MoveLeft(p,1); else //右兄弟不够借 Combine(p,1); else if(i==p->keynum) //删除的是最右边关键字 if(p->ptr[i-1]->keynum>Min) //左结点可以借 MoveRight(p,i); else //左结点不够借 Combine(p,i); else if(p->ptr[i-1]->keynum>Min) //删除关键字在中部且左结点够借 MoveRight(p,i); else if(p->ptr[i+1]->keynum>Min) //删除关键字在中部且右结点够借 MoveLeft(p,i+1); else //删除关键字在中部且左右结点都不够借 Combine(p,i); }
int FindBTNode(BTree p,KeyType k,int &i){ //反映是否在结点p中是否查找到关键字k if(k<p->key[1]){ //结点p中查找关键字k失败 i=0; return 0; } else{ //在p结点中查找 i=p->keynum; while(k<p->key[i]&&i>1) i--; if(k==p->key[i]) //结点p中查找关键字k成功 return 1; } }
int BTNodeDelete(BTree p,KeyType k){ //在结点p中查找并删除关键字k int i; int found_tag; //查找标志 if(p==NULL) return 0; else{ found_tag=FindBTNode(p,k,i); //返回查找结果 if(found_tag==1){ //查找成功 if(p->ptr[i-1]!=NULL){ //删除的是非叶子结点 Substitution(p,i); //寻找相邻关键字(右子树中最小的关键字) BTNodeDelete(p->ptr[i],p->key[i]); //执行删除操作 } else Remove(p,i); //从结点p中位置i处删除关键字 } else found_tag=BTNodeDelete(p->ptr[i],k); //沿孩子结点递归查找并删除关键字k if(p->ptr[i]!=NULL) if(p->ptr[i]->keynum<Min) //删除后关键字个数小于MIN AdjustBTree(p,i); //调整B树 return found_tag; } }
void BTreeDelete(BTree &t,KeyType k){ //构建删除框架,执行删除操作 BTNode *p; int a=BTNodeDelete(t,k); //删除关键字k if(a==0) //查找失败 printf(" 关键字%d不在B树中\n",k); else if(t->keynum==0){ //调整 p=t; t=t->ptr[0]; free(p); } }
void DestroyBTree(BTree &t){ //递归释放B树 int i; BTNode* p=t; if(p!=NULL){ //B树不为空 for(i=0;i<=p->keynum;i++){ //递归释放每一个结点 DestroyBTree(*&p->ptr[i]); } free(p); } t=NULL; }
int print(BTree p) { if(p==NULL) return 0; BTree q; printf("["); for(int i = 1;i <= p->keynum;i++) { printf("%d ",p->key[i]); } printf("]"); for(int i = 0;i < p->keynum+1;i++) { if(p->ptr[i]!=NULL) { q = p->ptr[i]; print(q); } } }
void Test(){ BTree T=NULL; Result s; //设定查找结果 KeyType a[]={45,24,70,7,30,53,90,3,12,26,37,50,61,85,100}; printf("创建一棵%d阶B树:\n",m); for(int j=0;j<15;j++){ //逐一插入元素 s=SearchBTree(T,a[j]); if(s.tag==0) InsertBTree(T,s.i,a[j],s.pt); printf(" \n第%d步,插入元素%d:\n ",j+1,a[j]); print(T); }
printf("\n"); printf("删除操作:\n"); KeyType k; //删除操作 k=7; BTreeDelete(T,k); printf(" 删除%d:\n ",k); printf(" 删除后的B树: \n"); print(T); printf("\n");
k=100; BTreeDelete(T,k); printf(" 删除%d:\n ",k); printf(" 删除后的B树: \n"); print(T); printf("\n");
printf(" 递归释放B树\n"); //递归释放B树 DestroyBTree(T); print(T); }
int main(){ Test(); return 0; }
|