B-树的实现(一)

B-树(多路平衡搜索树)的定义虽然比较简单,寥寥几条:

1.m阶B-树,最多只能有m个分支。

2.m阶B-树的关键字个数要介于[m/2](向上取整)-1和m-1之间(根节点除外)

3.关键字内部按升序排列

4.所有叶子节点一定在同一层

根据定义来实现B-树的难点在第二条,这就会导致分裂和合并的情况。

图文讲解可以看下面这个博客,非常的详细:

 http://www.cnblogs.com/nullzx/

下面来展示对B-树的实现(伪代码),其实伪代码才是精髓,看了别人的实现方法才知道什么叫大道至简:

1.插入操作:

#define m 4

//B-树的数据结构
typedef struct node{
	int Numbers;                        //节点关键字个数
	ValueType val[m+1];                 //节点数据
	KeyType Key[m+1];                   //节点键值
	struct node *ptr[m+1];              //分支指针
	struct node *Parent;                //父节点指针
}BNode,*PBNode;

//传递查找信息
typedef struct re{
	bool tag;                    //1表示查找到,0表示未查找到
	int Index;                   //查找到的下标
	PBNode Result;               //记录最后查找的节点
}Record;

bool InsertKey(PBNode *Root,KeyType Key,ValueType Value)
{//PBNpde 是根节点,Key是键值,Value是键对应的值
     //finish 是帮助判断迭代操作是否完成
     bool finish;                
     while(!finish && p)
     {                
         Record Re;
         if(Search((*Root),&Re,Key));
            if find modify Value and return;
         else
         {
             InsertInNode(PBNode p,KeyType Key,ValueType Value,int InsertIndex);
             //p是将要插入的节点(根据Search函数可以实现),InsertIndex是要插入的位置
             if(p->Numbers >= m)
             //如果插入后节点中的关键字大于上限那么进行分裂操作
                DividNode(p); 
             //如果存在父节点
             if(p->Parent)
                 //分裂后父节点的关键字个数满足条件,那么结束操作
                 if(p->Parent->Numbers < m-1)
                     finish = true;
             //分裂到根节点,需要重新生成一个根节点
             else
             {
                 NewARoot();
                 finish = true;
             }
             //否则更新相关变量,继续迭代
             else
                 Refresh();            
         }//else
     }//while
     //如果传入节点好似空则新生成一个节点
     if(!p)
        NewARoot();
}//InsertKey()

2、删除操作:

bool DeleteKey(PBNode *Root,KeyType Key,ValueType Value)
{
    //Border是[m/2]-1向上取整,代表节点键个数的下边界
    int Border = (m%2==0) ? (m/2-1):(m/2); 
    //帮助完成迭代的标志
    bool finish = false;
    if(!Search((*Root),Key))
        Not found and return;
    while(!finish)
    {
        //是叶子节点并且该节点的关键字个数本来就大于边界值,那么直接删除
        if(IsLeave(p) && P->Numbers > Border)
            Delete Key and finish is true;
        //是叶子节点并且该节点的关键字个数小于边界值但是做或者右兄弟的关键字个数有多余
        else if(IsLeave(p) && p->Numbers == Border && (p->LeftSilb->Numbers > Border || p->RightSilb->Numbers > Border))
        //从左兄弟或者有兄弟借关键字,DeleteIndex表示在该节点要删除的键的位置
            LeftKeyToRight(PBNode Left,PBNode Right,PBNode Parent,int DeleteIndex);
       OR   
            RightKeyToLeft(PBNode Left,PBNode Right,PBNode Parent,int DeleteIndex);
       AND
            finish = true;
        //是叶子节点,但是左右兄弟和本节点的关键字个数都等于边界值,那么从父节点拿关键字并且合并左
        //或者右节点
        else if(IsLeave(p) && p->Numbers == Border && (p->LeftSilb->Numbers == Border || p->RightSilb->Numbers == Border))
        {
            ParentKeyToSonAndMerge(PBNode Left,PBNode Right,PBNode Parent,Int DeleteIndex);
            //从父节点借下节点之后如果父节点的关键字个数小于边界值,那么需要迭代操作
            if(Parent->Numbers >= Border)
                finish = true;
            else
                Refresh();
        }
        //删除的是非叶子节点
        else
            //和叶子节点的值左为交换,然后利用迭代删除
            RotateToLeave();
    }//while
}

3、查找:

//在指定节点查找,但是并不一定会查找到,有可能查找的是插入的下标
int Search(PBNode Node,char Key)
{
	if(!Node)
		return -1;
	int i,j = -1;
    //利用的原理是节点内部的关键字是按照升序排列
	for(i = 0;i < Node->Numbers;i++)
	{
		if(Node->Key[i] < Key)
			j = i;
	}
	return j;
}

bool SearchKey(PBNode Root,Record *Re,KeyType Key)
{//Re是用来记录查找的信息的,因为有可能查找失败(插入的时候调用)那么久返回需要插入的节点的信息
    p = Root;    
    //要么查找到要么查找到叶子节点返回需要插入的节点的信息
    while(!IsLeave(p))
    {
        int K = search(p,Key);
        if(p->Key[k+1] == Key)
            find and return true;
        //继续深入子树
        p = p->ptr[k+1];
    }
    return false;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
定义B-存储结构(要求m3;为方便操作,结点中增加双亲结点指针域,最底层的Fail结点用NULL指针表示并且所有结点均存储于内存)。定义B-插入关键字函数、删除关键字函数、查找关键字函数以及按层次遍历输出B-所有结点的函数。主函数定义菜单(1.插入关键字 2.删除关键字 3. 查找关键字 4.层次遍历输出B-所有结点 5.结束程序)。 1. 插入关键字功能的输入为一个关键字,输出为新插入关键字所在结点的信息。 要求结点信息输出格式如下所示: (R102, n, K1, K2, …, Kn) R102表示结点位置,R表示根结点指针;第一个数字1表示根结点的A[1]指针,第二个数字0表求R->A[1]所指结点的A[0]指针,第三个数字2表示R->A[1]->A[0]所指结点的A[2]指针,即该结点指针为: R->A[1]->A[0]->A[2](该结点在第4层上)。n为该结点的关键字数目,K1, K2, …, Kn为该结点中n个非递减有序的关键字。 2. 删除关键字功能的输入为一个关键字,输出为删除成功与失败的信息。 3. 查找关键字功能的输入为一个关键字,输出为查找成功与失败的信息,查找成功时,应输出关键字所在结点信息(结点信息输出方法同1.)。 4. 按层次遍历输出B-所有结点功能的输入为一个字符文件名,输出为该字符文件,字符文件中,一个结点的信息输出一行(结点信息输出方法同1.),结点输出次序为按层次号由小到大并且同层结点从左向右。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值