关于上一篇文章《B-树及B+树》的bug

偶然在网上找到上一篇文章《B-树及B+树》,本想利用一下,但是发现了一个bug:当树高于3时,算法的输出是错误的。于是在下面把源代码罗列出来,其中

if(ap->son[0]!=NULL) ap->son[0]->parent=ap;

……

if(ap->son[i-s]!=NULL) ap->son[i-s]->parent=ap;

是自己为修复bug添加的代码。

#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <string.h>

using namespace std;

#define M 4        //B-树的阶,暂设为4
#define false 0
#define true 1

typedef struct BTNode
{
		//n个关键字,n+1个指针的结点的一般形式为:(n,P0,K1,P1,K2,P2,…,Kn,Pn) 
    int                keynum;            //节点中关键字个数,即节点的大小
    struct BTNode    *parent;        //指向双亲结点
    int                key[M+1];        //关键字向量,0号单元未用,key[1...M]存放第1至第M个关键字
    struct BTNode    *son[M+1];        //子树指针向量
}BTNode, *BTree;        //B-树节点和B-树的类型

typedef struct
{
    BTNode            *pt;            //指向找到的节点
    int                pos;                //1...M,在节点中的关键字序号
    int                tag;            //1:查找成功,0:查找失败
}Result;        //B-树的查找结果类型


//初始化
void init_BTree(BTree &root)
{
    root=NULL;
}

//在节点的关键字集中查找关键字key的插入位置
int search(BTree &p,int key)
{
    int j=0;
    for(j=1; j<=p->keynum; j++)
    {
        if(p->key[j] > key)
            break;
    }
    return j-1;        //应该插入的位置的前一位
}

Result searchBtree(BTree &root, int key)
{
    /*
    在m阶B树root中查找关键字key,返回(pt,i,tag).
    若查找成功,则特征值tag=1,指针pt所指结点中第i个关键字等于key;
    否则,特征值tag=0,关键字等于key的记录,应插入在指针pt所指结点中第i个和第i+1个关键码之间
    */
    
    int found=false;
    int i=0;
    BTree p=root,father=NULL;    //初始化p指向待查节点,father指向p的双亲
    Result    result;        //SearchBTree函数返回值

    while(p && !found)//直到查到,或者当前结点为叶子结点为止
    {
        i=search(p,key);    //p->node[i].key≤K<p->node[i+1].key.
        if(i>0 && p->key[i]==key)
        {
            found=true;        //找到待查关键字
        }
        else 
        {
            father=p;
            p=p->son[i];//去father的son[i]中查
        }
    }
    result.pos=i+1;        //pos是插入的位置,记住加1
    if(found)    //查找成功
    {
        result.pt=p;
        result.tag=1;    
    }
    else    //查找不成功,返回key的插入位置i
    {
        result.pt=father;
        result.tag=0;    
    }
    return result;
}//SearchBTree

//细胞分裂
void split(BTree &q, int s, BTree &ap)
{
    // 将结点q分裂成两个结点,前一半保留,后一半移入新生结点ap
    int i=0;
    cout<<"split!"<<"  "<<q->key[s]<<endl;
    ap=(BTree)malloc(sizeof(BTNode));        //生成新结点ap
    ap->son[0] = q->son[s];            //原来结点中间位置关键字相应指针指向的子树放到新生成结点的0棵子树中去
    if(ap->son[0]!=NULL)
    	ap->son[0]->parent=ap;
    for(i=s+1;i<=M;i++)        //后一半移入ap
    {
        ap->key[i-s]=q->key[i];
        ap->son[i-s]=q->son[i];
        if(ap->son[i-s]!=NULL)
        	ap->son[i-s]->parent=ap;
    }//for
    ap->keynum=M-s;
    ap->parent=q->parent;
    q->keynum=s-1;        //q的前一半保留,修改keynum
}//split

void NewRoot(BTree &root, int x, BTree &ap)        //生成新的根节点
{
    //生成含信息(root,r,ap)的新的根结点*root,原root和ap为子树指针
    BTree p;
    p=(BTree)malloc(sizeof(BTNode));
    if(root)    //如果原来的树不是空树
        root->parent=p;                    //远来的根的双亲指针指向新根
    p->son[0]=root;                        //新根的第一个孩子节点是原来的根节点
    root=p;        //root指向新根    
    root->parent=NULL;                    //新根的双亲是空指针
    root->keynum=1;            
    root->key[1]=x;                        //新根的第一个关键字就是前面分裂出来的关键字
    root->son[1]=ap;                    //新根的第二个孩子节点是原来的根中分裂出来的节点
    if(ap)        //如果原来的树不是空树
        ap->parent=root;                //原来的根中分裂出来的节点的双亲指针指向新根
}//NewRoot

//插入
void insert(BTree &q, int i, int key, BTree &ap)
{
    int j=0;
    for(j=q->keynum; j>=i; j--)
    {
        q->key[j+1]=q->key[j];//后移
    }
    q->key[i]=key;
    for(j=q->keynum; j>=i; j--)
    {
        q->son[j+1]=q->son[j];
    }
    q->son[i]=ap;
    q->keynum++;
}//insert


void insertBtree(BTree &root, int key, BTree &q, int i)
{
    //在B-树root中节点q的key[i]和key[i+1]之间插入关键字key
    //若引起节点过大,则沿双亲链进行必要的节点分裂整理,使root仍是M阶的B-树
    BTree ap=NULL;
    int x=key;
    int finished = false;
    int s=0;
    while(q && !finished)
    {
        insert(q, i, x, ap);    //将key和ap分别插入到q->key[i+1]和q->son[i+1]
        if(q->keynum<M)
            finished = true;    //插入完成
        else
        {    //分裂结点*q
            s=ceil(M/2);
            x=q->key[s];
            split(q, s, ap);    //将q->key[s+1...M],q->son[s...M]移入到新节点*ap
            q=q->parent;
            if(q)
                i=search(q,x)+1;        //在双亲结点*q中去查找x的插入位置,记住加1,因为search()返回的是插入位置的前一位
        }//else
    }//while
    if(!finished)                //root是空树(参数q初值为NULL)或者根节点已分裂为节点*q和*ap
        NewRoot(root, x, ap);    //生成含信息(root,x,ap)的新的根节点*root,原root和ap为子树指针
 }//insertBtree

void SearchInsertBTree(BTree &root,int key)//搜索插入
{ 
    //在m阶B树*t上结点*q的key[i],key[i+1]之间插入关键码key
    //若引起结点过大,则沿双亲链进行必要的结点分裂调整,使*t仍为m阶B树
    Result    rs;
    rs = searchBtree(root,key);
    if(!rs.tag)    //tag=0查找不成功,插入
    {
        cout<<"not exist the key word,insert the node!"<<endl;
        insertBtree(root, key, rs.pt, rs.pos);    //在B-树T上节点re.pt的key[i]和key[i+1]之间插入关键字key
    }
    else
    {
        cout<<"already exist the key word!"<<endl;
    }
}//InserBTree 

void DestroyBTree(BTree &root)
{
    int i=0;
    if(root) //非空树
    {
         for(i=0; i<=root->keynum; i++)
             if(root->son[i])
                DestroyBTree(root->son[i]);
         free(root);
         root=NULL;
         cout<<endl<<"destroy success"<<endl;
    }//if
}

//搜索关键字
void UserSearch(BTree &root,int key)
{
    Result s;
    s=searchBtree(root,key);
    if(s.tag)
        cout<<"find the key word!"<<endl;
    else
        cout<<"don't find the key word!"<<endl;
}//UserSearch


void print(BTree &p,int i) // TraverseBTree()调用的函数
{
    cout<<p->key[i]<<"  ";
}//print


void TraverseBTree(BTree &root)    //按关键字的顺序遍历B_树
{
    int i=0;
    if(root)    //非空树
    {
        if(root->son[0])    //有第0棵子树
        {
            TraverseBTree(root->son[0]);
        }
        for(i=1; i<=root->keynum; i++)
        {
            print(root,i);
            if(root->son[i])    //有第i棵子树
            {
                TraverseBTree(root->son[i]);
            }
        }//for
    }//if
}//TraverseBTree

int main()
{
    BTree Root;
    init_BTree(Root);            //初始化

    //插入测试
    int key;
    /*cout<<"输入要插入的节点,以0结束输入:"<<endl;
    cin>>key;
    while(key)
     {
        SearchInsertBTree(Root,key);
        cin>>key;
    }*/
   /* SearchInsertBTree(Root,45);*/
    SearchInsertBTree(Root,24);
    SearchInsertBTree(Root,53);
    SearchInsertBTree(Root,90);
    SearchInsertBTree(Root,3);
    SearchInsertBTree(Root,37);
    SearchInsertBTree(Root,50);
    SearchInsertBTree(Root,61);
    SearchInsertBTree(Root,70);
    SearchInsertBTree(Root,1);
    SearchInsertBTree(Root,2);
    SearchInsertBTree(Root,3);
    SearchInsertBTree(Root,4);
    SearchInsertBTree(Root,5);
    SearchInsertBTree(Root,6);
    SearchInsertBTree(Root,7);
    SearchInsertBTree(Root,8);
    SearchInsertBTree(Root,9);
    SearchInsertBTree(Root,10);
    SearchInsertBTree(Root,11);
    SearchInsertBTree(Root,12);
    SearchInsertBTree(Root,13);
    SearchInsertBTree(Root,999);
    SearchInsertBTree(Root,76);
    SearchInsertBTree(Root,15);
    SearchInsertBTree(Root,37);
    SearchInsertBTree(Root,45);
    SearchInsertBTree(Root,31);
    SearchInsertBTree(Root,0);
    SearchInsertBTree(Root,21);
    

    //打印测试
    cout<<endl<<"B-Tree order by key word:"<<endl;
    TraverseBTree(Root);
    
    //查找测试
    cout<<endl<<"please input the value of node which you will query.zero can end the input:"<<endl;
    cin>>key;
    while(key)
    {
        UserSearch(Root,key);
        cin>>key;
    }
    
    //销毁测试
    DestroyBTree(Root);//销毁B-树
    return 0;
}/*End of main()*/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值