偶然在网上找到上一篇文章《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()*/