B樹相關操作
阿新 • • 發佈:2018-12-25
花了一個下午把書上的B樹操作看明白了,又花了一天把程式碼憋出來…主要是操作比較複雜,需要注意的細節太多…至於刪除操作,書上已經詳細說明了過程…累啊
有一個不確定的地方是,不清楚如果重複資料有或者比較多的情況會怎麼樣
輸入樣例
21
F S Q K C L H T V W M R N P A B X Y D Z E
2
M T
#include<stdio.h>
#include<stdlib.h>
#define t 2
typedef struct Bnode{
int n;
int leaf;
char key[t*2-1];
struct Bnode *c[2*t];
}Bnode;
typedef struct Btree{
Bnode *root;
}Btree;
int Bcreate(Btree *T)
{
T->root=(Bnode *)malloc(sizeof(Bnode));
T->root->n=0;
T->root->leaf=1;
return 0;
}
int Bsplitchild(Bnode *x,int i)
{
Bnode *y,*z;
y=x->c[i];
z=(Bnode *)malloc(sizeof(Bnode ));
z->leaf=y->leaf;
z->n=t-1;
for (int j=0;j<t-1;j++)
z->key[j]=y->key[t+j];
if (!z->leaf)/*儘量不要操作沒有初始化的指標,養成良好的習慣還是很重要滴*/
for (int j=0;j<t;j++)
z->c[j]=y->c[j+t];
for (int j=x->n-1;j>=i;j--)
x->key[j+1]=x->key[j];
x->key[i]=y->key[t-1 ];
for (int j=x->n;j>i;j--)
x->c[j+1]=x->c[j];
x->c[i+1]=z;
x->n++;
y->n=t-1;
return 0;
}
int Binsert_nonfull(Bnode *x,char k)
{
if (x->leaf)
{
int i;
for (i=x->n-1;i>=0 && k<=x->key[i];i--)
x->key[i+1]=x->key[i];
i++;
x->key[i]=k;
x->n++;
return 0;
}
int i;
for (i=x->n-1;i>=0 && k<=x->key[i];i--);
i++;
if (x->c[i]->n==t*2-1)
{
Bsplitchild(x,i);
if (k>x->key[i])/*這裡不要忘了*/
i++;
}
Binsert_nonfull(x->c[i],k);
return 0;
}
int Binsert(Btree *T,char k)
{
Bnode *root=T->root;
if (root->n==t*2-1)
{
Bnode *s;
s=(Bnode *)malloc(sizeof(Bnode));
s->n=0;
s->leaf=0;
s->c[0]=root;
T->root=s;
Bsplitchild(s,0);
}
Binsert_nonfull(T->root,k);
return 0;
}
Bnode *Bsearch(Bnode *x,char k,int *i)
{
int j;
int n=x->n;
for (j=n-1;j>=0 && k<=x->key[j];j--);
j++;
if (/*j>=0 && */j<n && k==x->key[j])
{
*i=j;
return x;
}
if (x->leaf)
{
*i=-1;
return NULL;
}
return Bsearch(x->c[j],k,i);
}
char successor(Bnode *x,int i)/*求內部節點的後繼*/
{
Bnode *tmp;
for (tmp=x->c[i+1];!tmp->leaf;tmp=tmp->c[0]);
return tmp->key[0];
}
char predecessor(Bnode *x,int i)/*求內部節點的前驅*/
{
Bnode *tmp;
for (tmp=x->c[i];!tmp->leaf;tmp=tmp->c[tmp->n]);
return tmp->key[tmp->n-1];
}
int Bmerge(Btree *T,Bnode *x,int i)/*合併x.key[i]的左右兩個孩子*/
{
Bnode *y=x->c[i];
Bnode *z=x->c[i+1];
y->key[y->n]=x->key[i];
int j;
for (j=0;j<t-1;j++)
y->key[t+j]=z->key[j];
for (j=0;j<t;j++)
y->c[t+j]=z->c[j];
y->n=t*2-1;
free(z);
for (j=i;j<x->n-1;j++)
x->key[j]=x->key[j+1];
for (j=i+1;j<x->n;j++)
x->c[j]=x->c[j+1];
x->n--;
if (x->n==0)/*一定是內部節點*/
{
free(x);
T->root=y;
}
return 0;
}
int Bdelete(Btree *T,Bnode *x,char k)/*疑似有bug,當有重複元素時不知道會不會出錯*/
{
int i;
for (i=x->n-1;i>=0 && k<=x->key[i];i--);
i++;
if (x->leaf)/*情況1*/
{
int j;
for (j=i;j<x->n-1;j++)
x->key[j]=x->key[j+1];
x->n--;
return 0;
}
if (i<x->n && x->key[i]==k)
if (x->c[i]->n>=t)/*情況2a*/
{
char k1=predecessor(x,i);
x->key[i]=k1;
Bdelete(T,x->c[i],k1);/*如果有重複的元素,也不會出錯*/
}
else
if (x->c[i+1]->n>=t)/*情況2b*/
{
char k1=successor(x,i);
x->key[i]=k1;
Bdelete(T,x->c[i+1],k1);
}
else/*情況2c*/
{
Bnode *y=x->c[i];
Bmerge(T,x,i);/*會刪除空的非內部空節點*/
Bdelete(T,y,k);
}
else
if (x->c[i]->n>=t)/*情況3,但是可以直接遞迴*/
Bdelete(T,x->c[i],k);
else
if (i>0 && x->c[i-1]->n>=t)/*情況3a左*/
{
Bnode *y=x->c[i];
Bnode *z=x->c[i-1];
int j;
for (j=y->n-1;j>=0;j--)
y->key[j+1]=y->key[j];
for (j=y->n;j>=0;j--)
y->c[j+1]=y->c[j];
y->key[0]=x->key[i-1];/*細節啊,害我除錯這麼久*/
y->c[0]=z->c[z->n];
y->n++;
x->key[i-1]=z->key[z->n-1];/*這裡也是!*/
z->n--;
Bdelete(T,y,k);
}
else
if (i<x->n && x->c[i+1]->n>=t)/*情況3a右,邊界檢查別忘了,雖然這裡沒有出錯*/
{
Bnode *y=x->c[i];
Bnode *z=x->c[i+1];
y->key[y->n]=x->key[i];
y->c[y->n+1]=z->c[0];
y->n++;
x->key[i]=z->key[0];
int j;
for (j=0;j<z->n-1;j++)
z->key[j]=z->key[j+1];
for (j=0;j<z->n;j++)
z->c[j]=z->c[j+1];
z->n--;
Bdelete(T,y,k);
}
else/*情況3b*/
{
Bnode *y=x->c[i];
Bmerge(T,x,i);
Bdelete(T,y,k);
}
return 0;
}
int print(Bnode *x)
{
int i;
int n=x->n;
printf("(");
for (i=0;i<n-1;i++)
printf("%c ",x->key[i]);
if (n)
printf("%c",x->key[i]);
printf(")");
if (x->leaf)
return 0;
for (i=0;i<=n;i++)
print(x->c[i]);
return 0;
}
int main(void)
{
Btree T;
Bcreate(&T);
int n;
scanf("%d\n",&n);
for (int i=0;i<n;i++)
{
char k;
scanf("%c ",&k);
Binsert(&T,k);
}
print(T.root);
printf("\n");
scanf("%d\n",&n);
for (int i=0;i<n;i++)
{
char k;
int j;
scanf("%c ",&k);
if (Bsearch(T.root,k,&j))
{
printf("%c deleted!:",k);
Bdelete(&T,T.root,k);
print(T.root);
printf("\n");
}
else
printf("%c:not exist!\n",k);
}
printf("\n");
return 0;
}