B树的基本例程:删除

摘要:删除操作与插入基本相似,但是比较复杂(算法部分取自算法导论)。
(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);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值