B樹相關操作

花了一個下午把書上的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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章