B树的基本例程:删除

来源:互联网 发布:美国网件访客网络 编辑:程序博客网 时间:2024/06/06 02:33

摘要:删除操作与插入基本相似,但是比较复杂(算法部分取自算法导论)。
(0)因为删除操作可以从任意内部节点删除,这导致必须安排它的子女;
(1)除了根节点,一定要保证删除不会使得该节点的元素个数少于t-1个.
(3)因此在递归降至某个节点之前,一定要保证它的父节点有t个子女.

下面分几种情况讨论B树删除的操作:
(1)如果关键字k在节点x中,且x是个叶子节点,则删除x;
(2)如果关键字k在节点x中且x是个内节点,则有如下操作;
a)如果节点x中前于k的子节点y包含至少k个关键字,则找出以y为根的子树前驱k’,递归的删除k’,并在x中用k’取代k.
b)对称的,如果节点x中位于k之后的子节点z包含至少t个关键字,则可以找出k在以z为根的子树中的后继k’,递归的删除k’,并用k’代替k。
c)如果关键字k的前后子节点都只有t-1个关键字,就将y和z合并到y,这使得x失去指向k和z的指针,释放z并将k从y中递归的删除z.
3)如果k不在内节点x中,则确定必包含k的正确子树的根ci[x],如果ci[x]只有t-1个关键字,执行步骤3(a/b),保证我们降至一个有t个关键字的节点.
a)如果ci[x]只有t-1个关键字,但他的一个兄弟包含t个关键字,则x中的某一个关键字降至ci[x],将ci[x]相邻兄弟的某一关键字上升到x。
b)如果ci[x]与相邻兄弟都只有t-1个关键字,就将ci[x]与一个兄弟合并,即将x的一个关键字降至新合并的节点(这里会让父节点减少,因此必须保证每一个节点被到达之前都有t的关键字,否则就需要回溯).

void combine(Position T,Position T2,int x){    //把关键字x,T2中所有的关键字合并入T    int max = maxIndex(T);    int j = 0;    T->data[max + 1] = x;//合并关键字与子节点    for(int i = max + 2;i<=2*DU-2;i++)        T->data[i] = T2->data[j++];       j = 0;    for(int i = max + 2;i<=2*DU-1;i++)        T->child[i] = T2->child[j++];}int FindPrevious(Position T)//前继{    int max = maxIndex(T);       while (!T->isLeaf)       {        T = T->child[max+1];        max = maxIndex(T);       }    return T->data[max];}int FindNext(Position T)//后继{    while(!T->isLeaf)        T = T->child[0];    return T->data[0];}void DeleteBtree(Position *T,int x){    int k,indexmax,j;    int temp,max;    Position C,Temp;//用来保存正确的子节点    if((*T) == NULL)        //没有删除成功        return;    int i = 0;    max = maxIndex(*T);    while(i<= max&&x>(*T)->data[i])        i++;    if  (i<=2*DU-2&&x == (*T)->data[i])        {            if ((*T)->isLeaf == 1)                //x在叶子节点上                shiftLeft(*T,i,1);//左移一位            else                //x在内节点            {                if(  pageSize((*T)->child[i]) >=DU )                {                    k = FindPrevious((*T)->child[i]);                    (*T)->data[i] = k;                    DeleteBtree( &(*T)->child[i],k);               }                else if ( pageSize((*T)->child[i+1]) >=DU )                {                    indexmax = maxIndex((*T)->child[i+1]);                    k = FindNext((*T)->child[i+1]);                    (*T)->data[i] = k;                    DeleteBtree( &(*T)->child[i+1],k);                }                else                {                    //合并                    combine((*T)->child[i],(*T)->child[i+1],x);                    free((*T)->child[i+1]);                    for( j = i;j<=2*DU-3;j++)                    {                        (*T)->data[j] = (*T)->data[j+1];                        (*T)->child[j+1] = (*T)->child[j+2];                    }                    (*T)->data[j] = 0;                    (*T)->child[j+1] = NULL;//以上为对T的关键字和子节点进行移动                    DeleteBtree(&(*T)->child[i],x);//在合并的新节点递归的删除关键字x                }        }//x 在内部节点    }//x在当前节点    else if ((*T)->isLeaf == 1)        puts("not found");    else     {        //继续向下找        C = (*T)->child[i];        if(pageSize(C) == DU-1)        {            max = maxIndex(*T)+1;            temp = -1;            //执行下列步骤保证降至一个包含t个关键字的节点            if(i == 0&&(pageSize((*T)->child[i+1]) >=DU))               temp = 0;//右兄弟            else if ( i == max&&(pageSize((*T)->child[i-1]) >=DU))                temp = 1;//左兄弟            else            {                    if(pageSize((*T)->child[i+1]) >=DU )                        temp = 0;                    else if (pageSize((*T)->child[i-1]) >=DU)                        temp = 1;            }                    //将*T中的合适关键字降入C中,将C的左/右兄弟的合适关键字放入Tif(temp == 0)//右兄弟                    {                        C->data[maxIndex(C)+1] = (*T)->data[0];//将T的最小关键字给C作为C的最大关键字                        C->child[maxIndex(C)+2] = (*T)->child[i+1]->child[0];//将右兄弟的最左子节点合并到C                        shiftLeft(*T,0,1);                        (*T)->data[maxIndex(*T)] = (*T)->child[i+1]->data[0];//将右兄弟最小关键字给T的最大                        shiftLeft((*T)->child[i+1],0,1);                    }                    else if (temp == 1)//左兄弟                    {                        max = maxIndex((*T)->child[i-1]);                        shiftRight(C,0);                        C->data[0] = (*T)->data[maxIndex(*T)];                        C->child[0] = (*T)->child[i-1]->child[max+1];                        (*T)->data[maxIndex(*T)] = (*T)->child[i-1]->data[max];//将左兄弟最大关键字给T                        shiftLeft( (*T)->child[i-1],max,1);//删除左兄弟的最大关键字                    }                else                    //合并C与左/右兄弟                {                    if (i== 0)                        //合并右兄弟                    {                    combine(C,(*T)->child[i+1],(*T)->data[i]);                    free((*T)->child[i+1]);                    for( j = i;j<=2*DU-3;j++)                    {                        (*T)->data[j] = (*T)->data[j+1];                        (*T)->child[j+1] = (*T)->child[j+2];                    }                    (*T)->data[i] = 0;                    (*T)->child[j] = NULL;//以上为对T的关键字和子节点进行移动                    }                    else                    {                        //合并左兄弟                        combine((*T)->child[i-1],C,(*T)->data[i-1]);                        free(C);                        C = (*T)->child[i-1];                    for( j = i;j<=2*DU-3;j++)                    {                        (*T)->data[j] = (*T)->data[j+1];                        (*T)->child[j] = (*T)->child[j+1];                    }                    (*T)->data[i-1] = 0;                    (*T)->child[j] = NULL;//以上为对T的关键字和子节点进行移动                    (*T)->child[j+1] = NULL;                    }                }        }                   // C满足至少t个节点,递归删除x        DeleteBtree( &C,x);    }    //检测是否为空,否则删除空根    if(pageSize(*T) == 0)    {        if ((*T)->parent == NULL)        {            Temp = *T;            (*T) = (*T)->child[0];            (*T)->parent = NULL;             free(Temp);        }    }}
0 0
原创粉丝点击