B树的实现

#include <stdio.h>
#include <stdlib.h>

#define MIN_DEGREE    (3)
#define MAX_KEY (2*MIN_DEGREE -1 )
#define true 1
#define false 0
#define NO_KEY 0
typedef int bool;
//B树节点结构
typedef struct BTreeNode
{
//当前存储的数据个数
    int KeyNumber;
//数据数组
    int Key[MAX_KEY];
//指针数组
    struct BTreeNode *KeyPointer[MAX_KEY + 1];
//是否是叶节点
    bool IsLeaf;
}BTreeNode;

//搜索B树返回结果
typedef struct SearchResult
{
//数据所在节点指针
    struct BTreeNode *Pointer;
//数据在节点中位置
    int KeyPosition;
}SearchResult;

void BTreeSplit(struct BTreeNode *Parent, int ChildPosition, struct BTreeNode *Child );
BTreeNode * BTreeInsertNonfull(struct BTreeNode *Pointer, int data);
void MergeNode(struct BTreeNode *Left, int data, struct BTreeNode *Right);
void DeleteData(struct BTreeNode *Pointer, int Position);

//函数目的:给一个节点分配空间
//接收参数:*Pointer - 节点指针
//返回参数:*Pointer - 节点指针
struct BTreeNode *AllocateNode(struct BTreeNode *Pointer)
{
    int i;

//分配内存空间
    Pointer = (struct BTreeNode *)malloc(sizeof(struct BTreeNode));

    for(i = 0; i <= MAX_KEY; i++)
        Pointer->KeyPointer[i] = NULL;

        Pointer->IsLeaf = true;
        Pointer->KeyNumber = 0;
    

    return Pointer;
}




//函数目的:在B树中递归的搜索给定的数据,如果存在则返回数据所在节点和在节点中的位置,不存在返回NULL
//接收参数:   *Root - 树的根节点指针
//                     data - 要搜索的数据
//返回参数:SearchResult - 数据所在节点和在节点中的位置
struct SearchResult BTreeSearch(struct BTreeNode *Root, int data)
{
    int i = 0;
    struct SearchResult Result;

//找到节点中数据所在位置
    while((i < Root->KeyNumber) && (Root->Key[i] < data))
        i++;

//数据找到,返回结果, 由于移除或移动的数据没有被改写, 
//Root->KeyPointer[KeyNumber]可能与data相同, 所以要判断i < Root->KeyNumber
    if((i < Root->KeyNumber) && (Root->Key[i] == data) )
    {
        Result.Pointer = Root;
        Result.KeyPosition = i;
        return Result;
    }

//已经搜索到叶节点,数据不存在,返回NULL
    if(Root->IsLeaf == true)
    {
        Result.Pointer = NULL;
        Result.KeyPosition = -1;
        return Result;
    }
//非叶节点,继续搜索子树节点
    else
        return BTreeSearch(Root->KeyPointer[i], data);
}

//函数目的:向树中插入一个数据
//接收参数:*Root - 树的根节点
//           data - 数据
//返回参数:根节点指针
struct BTreeNode *BTreeInsert(struct BTreeNode *Root, int data)
{
    struct BTreeNode *NewNode = NULL;
    SearchResult      seResult;
    //BTreeNode *Pointer = NULL;

    seResult = BTreeSearch(Root, data);

    if(seResult.Pointer != NULL)
    {
        printf("the data(%d) already in the tree \n", data);
        return Root;
    }

//检查是否根节点已满,如果已满,分裂并生成新的根节点
    if(Root->KeyNumber == MAX_KEY )
    {
        NewNode = AllocateNode(NewNode);
        NewNode->IsLeaf = false;
        NewNode->KeyNumber = 0;
        NewNode->KeyPointer[0] = Root;
        BTreeSplit(NewNode, 0, Root);
        BTreeInsertNonfull(NewNode, data);

        return NewNode;
    }
//还没到最大数据数,直接插入
    else
    {
        BTreeInsertNonfull(Root, data);
        return Root;
    }

}

//函数目的:分裂存储数达到最大的节点
//接收参数:*Parent - 分裂节点的双亲节点指针
//           *Child - 指向分裂节点的指针
//    ChildPosition - 分裂节点在双亲节点中的位置
//返回参数:无
void BTreeSplit(struct BTreeNode *Parent, int ChildPosition, struct BTreeNode *Child )
{
    int i;
    struct BTreeNode *NewNode= NULL;

//为新分裂出的节点分配空间
    NewNode = AllocateNode(NewNode);
//与被分裂点同级
    NewNode->IsLeaf = Child->IsLeaf;
//设置节点数
    NewNode->KeyNumber = MIN_DEGREE - 1;

//复制数据(key)
    for(i = 0; i < MIN_DEGREE - 1; i++)
        NewNode->Key[i] = Child->Key[i + MIN_DEGREE];

//如果不是叶节点,复制指针
    if(false == Child->IsLeaf)
    {
        for(i = 0; i < MIN_DEGREE; i++)
            NewNode->KeyPointer[i] = Child->KeyPointer[i + MIN_DEGREE];
    }

    Child->KeyNumber = MIN_DEGREE - 1;

//将中间数作为索引插入到父亲节点中
    for(i = Parent->KeyNumber; i > ChildPosition; i--)
    {
        Parent->Key[i] = Parent->Key[i - 1];
        Parent->KeyPointer[i + 1] = Parent->KeyPointer[i];
    }

    Parent->Key[i] = Child->Key[MIN_DEGREE - 1];
    Parent->KeyNumber++;
    Parent->KeyPointer[i + 1] = NewNode;
}

//函数目的:向非满的节点中插入一个数据
//接收参数:*Pointer - 指向节点的指针
//       data - 插入的数据
//返回参数:插入数据的node
BTreeNode * BTreeInsertNonfull(struct BTreeNode *Pointer, int data)
{
    int i;
    struct BTreeNode *Child= NULL;

    i = Pointer->KeyNumber;

//如果是叶节点,直接插入数据
    if(Pointer->IsLeaf == true)
    {
        //移动数据
        while((i > 0) && (Pointer->Key[i - 1] > data))
        {
            Pointer->Key[i] = Pointer->Key[i - 1];
            i--;
        }

        //插入数据
        Pointer->Key[i] = data;
        Pointer->KeyNumber++;

        return Pointer;
    }
//不是叶节点,找到数据应插入的子节点并插入
    else
    {
        while((i > 0) && (Pointer->Key[i - 1] > data))
            i--;

        Child = Pointer->KeyPointer[i];

        if(Child->KeyNumber == MAX_KEY)
        {
            BTreeSplit(Pointer, i, Child);

            if(data > Pointer->Key[i])
                i++;
        }

        Child = Pointer->KeyPointer[i];
        return BTreeInsertNonfull(Child, data);
    }
}


int BTreeDelete(struct BTreeNode **pRoot, int data)
{
    struct SearchResult Result;
    struct BTreeNode *Pointer= NULL, *TempPointer= NULL;
    int i, Temp = 0, j;
    BTreeNode*        Root= NULL;

    Root = *pRoot;

    Result = BTreeSearch(Root, data);
    Pointer = Result.Pointer;

//数据不在树中,返回失败
    if(Pointer == NULL)
    {
        printf(" the data(%d) is not in the tree\n", data);

        return 1;
    }
//数据在Root中
    if(Pointer == Root)
    {
        //Root是叶节点   这里是算法导论中的 1)
        if(Pointer->IsLeaf == true)
        {
            DeleteData(Result.Pointer, Result.KeyPosition);

            return 0;
        }
        //Root是中间结点
        else
        {
            //前于数据的子节点中包含多于最小值个数据 算法导论: 2a
            if(Root->KeyPointer[Result.KeyPosition]->KeyNumber >= MIN_DEGREE)
            {
                //找到数据的前驱
                TempPointer = Root;
                Temp = Result.KeyPosition;

                while(TempPointer->KeyPointer[Temp]->IsLeaf == false)
                {
                    TempPointer = TempPointer->KeyPointer[Temp];
                    Temp = TempPointer->KeyNumber;
                }

                //记录前驱
                TempPointer = TempPointer->KeyPointer[Temp];
                Temp = TempPointer->KeyNumber - 1;
                Temp = TempPointer->Key[Temp];
                //删除前驱
                TempPointer = Root->KeyPointer[Result.KeyPosition];
                BTreeDelete(&TempPointer, Temp);
                //用前驱替换数据
                Root->Key[Result.KeyPosition] = Temp;

                return 0;
            }

            //位于数据之后的子节点中包含多于最小值个数据 算法导论 2b
            if(Root->KeyPointer[Result.KeyPosition + 1]->KeyNumber >= MIN_DEGREE)
            {
                //找到数据的后继
                TempPointer = Root;
                Temp = Result.KeyPosition;

                if(TempPointer->KeyPointer[Temp + 1]->IsLeaf == true)
                {
                   TempPointer = TempPointer->KeyPointer[Temp + 1];
                   
                }
                else
                {
                    TempPointer = TempPointer->KeyPointer[Temp + 1];
                    
                    while(TempPointer->KeyPointer[0]->IsLeaf == false)
                    {
                        TempPointer = TempPointer->KeyPointer[0];
                    }

                    //记录后继
                    TempPointer = TempPointer->KeyPointer[0];
                }

                
                Temp = TempPointer->Key[0];

                TempPointer = Root->KeyPointer[Result.KeyPosition + 1];
                //删除后继
                BTreeDelete(&TempPointer, Temp);
                //用后继替换数据
                Root->Key[Result.KeyPosition] = Temp;

                return 0;
            }

            //子节点都只含有最小值个数据
            //合并两个子节点和数据data   算法导论 2c
            //i = Root->KeyPointer[Result.KeyPosition + 1]->KeyNumber;
            //把右子节点中数据和指针移动到左子节点中
            MergeNode(Root->KeyPointer[Result.KeyPosition], Root->Key[Result.KeyPosition],
                      Root->KeyPointer[Result.KeyPosition + 1]);

            TempPointer = Root->KeyPointer[Result.KeyPosition];
            //释放右节点内存
            free(Root->KeyPointer[Result.KeyPosition + 1]);
            //删除数据和指向右子节点的指针
            i = Result.KeyPosition;

            while(i < Root->KeyNumber - 1)
            {
                Root->Key[i] = Root->Key[i + 1];
                Root->KeyPointer[i + 1] = Root->KeyPointer[i + 2];
                i++;
            }

            Root->KeyNumber--;
            
            //Root可能要被删除, 所以要更新
            if(NO_KEY == Root->KeyNumber)
            {
                free(Root);
                
                //Root = TempPointer;
                *pRoot = TempPointer;
            }

            //删除数据
            return BTreeDelete(&TempPointer, data);

            
        }
    }
//数据不在Root中
    else
    {
        //找到数据所在子节点的根
        i = 0;

        while((Root->Key[i] < data) && (i < Root->KeyNumber))
            i++;

        TempPointer = Root->KeyPointer[i];
        Temp = i;

        //这个节点中只有最小数的数据  算法导论 3
        if(TempPointer->KeyNumber == MIN_DEGREE - 1)
        {
            //左兄弟节点中有多于最小数的数据  算法导论 3a1
            if((i > 0) && (Root->KeyPointer[i - 1]->KeyNumber >= MIN_DEGREE))
            {
                //下面的操作相当于右旋转

                //把父节点中数据降至节点, 放在右子树的最前
                //BTreeInsertNonfull(TempPointer, Root->Key[i - 1]);
                //先将之节点的数据右移给父节点数据空出位置
                for(j = TempPointer->KeyNumber; j > 0; j-- )
                {
                    TempPointer->Key[j] = TempPointer->Key[j - 1];
                    TempPointer->KeyPointer[j+1]= TempPointer->KeyPointer[j];
                }
                //最前的指针右移
                TempPointer->KeyPointer[1]= TempPointer->KeyPointer[0];

                //插入父节点
                TempPointer->Key[0] = Root->Key[i - 1];
                TempPointer->KeyNumber++;
                
                //把左兄弟节点最右指针移动过来
                TempPointer->KeyPointer[0] =
                    Root->KeyPointer[i - 1]->KeyPointer[Root->KeyPointer[i - 1]->KeyNumber];
                //把左节点数据升至父节点
                Root->Key[i - 1] = Root->KeyPointer[i - 1]->Key[Root->KeyPointer[i - 1]->KeyNumber - 1];


                //delete the last key of left brother
                //DeleteData(Root->KeyPointer[i - 1], Root->KeyPointer[i - 1]->KeyNumber - 1);

                Root->KeyPointer[i - 1]->KeyNumber--;

                return BTreeDelete(&TempPointer, data);
                
            }
            //右兄弟节点中有多于最小数的数据  算法导论 3a2
            else if((i < Root->KeyNumber) &&
                    (Root->KeyPointer[i + 1]->KeyNumber >= MIN_DEGREE))
            {
                //下面的操作相当于左旋转
                
                //把父节点中数据降至节点, 父节点在放在左子树的最后
                TempPointer->Key[TempPointer->KeyNumber] = Root->Key[i];
                TempPointer->KeyNumber++;
                //BTreeInsertNonfull(TempPointer, Root->Key[i]);
                //把右兄弟节点最左指针移动过来
                TempPointer->KeyPointer[TempPointer->KeyNumber] =
                    Root->KeyPointer[i + 1]->KeyPointer[0];
                //把右节点数据升至父节点
                //BTreeInsertNonfull(Root, Root->KeyPointer[i + 1]->Key[0]);
                Root->Key[i] = Root->KeyPointer[i + 1]->Key[0];  

                //
                //for(j = 0; ; j > Root->KeyPointer[i + 1]->KeyNumber; j++)
                //{
                 //   TempPointer->Key[j] = TempPointer->Key[j-1];
                 //   TempPointer->KeyPointer[j + 1] = TempPointer->KeyPointer[j];
                    
                //}

                
                DeleteData(Root->KeyPointer[i + 1], 0);

                return BTreeDelete(&TempPointer, data);
            }
            //兄弟节点都只有最小数据数的数据  算法导论 3b
            else
            {
                //没有左兄弟,与右兄弟合并
                if(i == 0)
                {
                    MergeNode(TempPointer, Root->Key[i], Root->KeyPointer[i + 1]);
                    //释放节点内存
                    free(Root->KeyPointer[i + 1]);

                    //BTreeInsertNonfull(TempPointer, Root->Key[i]);

                    //删除数据和指向节点的指针
                    while(i < Root->KeyNumber - 1)
                    {
                        Root->Key[i] = Root->Key[i + 1];
                        Root->KeyPointer[i + 1] = Root->KeyPointer[i + 2];
                        i++;
                    }

                    Root->KeyNumber--;
                    if(NO_KEY == Root->KeyNumber)
                    {
                        free(Root);
                        
                        //Root = TempPointer;
                        *pRoot = TempPointer;
                    }
                    return BTreeDelete(&TempPointer, data);
                }
                //否则与左兄弟合并
                else
                {
                    MergeNode(Root->KeyPointer[i - 1], Root->Key[i - 1], TempPointer);
                    //释放节点内存
                    free(TempPointer);
                    Temp = i - 1;

                    TempPointer = Root->KeyPointer[i - 1];

                    //BTreeInsertNonfull(Root->KeyPointer[i - 1], Root->Key[i - 1]);

                    //删除数据和指向节点的指针
                    while(i < Root->KeyNumber)
                    {
                        Root->Key[i - 1] = Root->Key[i];
                        Root->KeyPointer[i] = Root->KeyPointer[i + 1];
                        i++;
                    }

                    Root->KeyNumber--;


                    if(NO_KEY == Root->KeyNumber)
                    {
                        free(Root);
                        //Root = TempPointer;
                        *pRoot = TempPointer;
                    }
                    return BTreeDelete(&TempPointer, data);
                }
            }
        }

        return BTreeDelete(&(Root->KeyPointer[Temp]), data);
    }
}

//函数目的:合并两个节点和父节点的一个数据
//接收参数:*Left - 左子节点指针
//          *Right - 右子节点指针
//           data - 父节点的一个数据
//返回参数:无
void MergeNode(struct BTreeNode *Left, int data, struct BTreeNode *Right)
{
    int i = 0;
    //BTreeNode * pTempNode;

//把数据插入到左子节点中
    //pTempNode = BTreeInsertNonfull(Left, data);

    Left->Key[Left->KeyNumber] = data;
    Left->KeyNumber++;

    

//把右子节点的数据和指针移动到左子节点中
    while(i < Right->KeyNumber)
    {
        Left->Key[i + Left->KeyNumber] = Right->Key[i];
        Left->KeyPointer[i + Left->KeyNumber] = Right->KeyPointer[i];
        i++;
    }

    //The last pointer should be move to left
    Left->KeyPointer[i + Left->KeyNumber] = Right->KeyPointer[i];

//改变左节点的数据数
    Left->KeyNumber = Left->KeyNumber + Right->KeyNumber;
}


//函数目的:删除节点中的数据
//接收参数:*Pointer - 节点指针
//          Position - 删除数据在节点中的位置
//返回参数:无
void DeleteData(struct BTreeNode *Pointer, int Position)
{
    int i;

//删除节点并移动数据和指针
    for(i = Position; i < Pointer->KeyNumber - 1; i++)
    {
        Pointer->Key[i] = Pointer->Key[i + 1];
        Pointer->KeyPointer[i] = Pointer->KeyPointer[i + 1];
    }

    Pointer->KeyPointer[Pointer->KeyNumber - 1] = Pointer->KeyPointer[Pointer->KeyNumber];

//减少节点的数据数
    Pointer->KeyNumber--;
}


//函数目的:建立一个B树
//接收参数:*Root - 树的根节点指针
//返回参数:*Root - 树的根节点指针
struct BTreeNode *BTreeCreate(struct BTreeNode *Root)
{
    Root = AllocateNode(Root);
    Root->IsLeaf = true;
    Root->KeyNumber = 0;
    return Root;
}


//函数目的:广度优先显示树
//接收参数:Root - 树的根节点
//返回参数:无
void BTreeDisplay(struct BTreeNode *Root)
{
    int i, QueueNumber = 0;
    struct BTreeNode *Queue[100], *CurrentNode;

//加入队列
    Queue[QueueNumber] = Root;
    QueueNumber++;

    while(QueueNumber > 0)
    {
        //出队
        CurrentNode = Queue[0];
        QueueNumber--;
        i = 0;

        while(i < QueueNumber)
        {
            Queue[i] = Queue[i + 1];
            i++;
        }

        //显示节点
        i = 0;

        while(i < CurrentNode->KeyNumber)
        {
            printf("|");
            printf("%d", CurrentNode->Key[i]);
            i++;
        }

        if(i != 0)
        {
            printf("|   ");
        }

        //子节点入队
        if(CurrentNode != NULL && CurrentNode->IsLeaf == false)
        {
            i = 0;

            while(i <= CurrentNode->KeyNumber)
            {
                Queue[QueueNumber] = CurrentNode->KeyPointer[i];
                QueueNumber++;
                i++;
            }
        }
    }

    printf("\n");
}

int main()
{
    struct BTreeNode *Root = NULL;
    int i = 0, choose = 0, a = 0;
    int re = 0;
    char c;
   

    Root = BTreeCreate(Root);

//BTreeTestA();
//BTreeTestB();
    while(choose != 3)
    {

        printf("input any character for continue \n");
        //for clean the stdin buff
        while ((c = getchar()) != '\n' && c != EOF ) ;
        printf("function\n");
        printf("1.insert\n");
        printf("2.delete\n");
        printf("3.quit\n");

        
        scanf("%d", &choose);

        if(choose == 1)
        {
            printf("please input insert the data, -1 exit\n");

            while(i != -1)
            {
                //for clean the stdin buff
                while ( (c = getchar()) != '\n' && c != EOF ) ; 
                //fflush(stdin);
                re = scanf("%d", &i);
                printf("data %d \n", i);
                //printf("re %d \n", re);
                //scanf("%d", &a);

                if(i != -1)
                {
                    Root = BTreeInsert(Root, i);
                    BTreeDisplay(Root);
                }


            }
        }
        else if(choose == 2)
        {
            printf("input the data need to be deleted  -2 exit\n");

            while(i != -2)
            {
                //for clean the stdin buff
                while ( (c = getchar()) != '\n' && c != EOF ) ; 
                scanf("%d", &i);
                printf("data %d \n", i);
                if(i != -2)
                {        
                    i = BTreeDelete(&Root, i);
                    BTreeDisplay(Root);
                }
            }
        }
    }

    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值