在B-树中查找给定关键字的方法是,首先把根结点取来,在根结点所包含的关键字K1,…,kj查找给定的关键字(可用顺序查找或二分查找法),若找到等于给定值的关键字,则查找成功;否则,一定可以确定要查的关键字在某个Ki或Ki+1之间,于是取Pi所指的结点继续查找,直到找到,或指针Pi为空时查找失败
代码:
头文件:BTree.h
#ifndef BTREE_H
#define BTREE_H
#define M 3 //B树的阶,暂设为3
#define N 17 //数据元素的个数
typedef struct BTNode{
int keynum; //结点中关键字的个数,即结点的大小
struct BTNode *parent; //指向双亲结点
struct Node{ //关键字向量
int key; //结点中的关键字
struct BTNode *ptr; //子树指针向量
int recptr; //记录指针向量
}node[M + 1]; //key,recptr的0号单元未用
}BTNode,*BTree; //B树结点和B树的类型
typedef struct{
BTNode *pt; //指向找到的结点
int i; // 1.....m,在所找到的结点中关键字序号
int tag; // 1:查找成功,0:查找失败
}Result; //B树的查找结果类型
//在p->node[1]....p->node[keynum]中查找k所处的位置p->node[i].key <= k < p->node[i+1].key
int Search(BTree p,int k);
//在M阶B树T上查找关键字K,返回结果Result
//查找成功,tag = 1,pt指向包函关键字K的结点,i为K在结点中的位置
//查找失败,tag = 0,pt指向K应插入的结点,i...i+1之间插入K
Result SearchBTree(BTree T,int k);
//将key插入到*q所指向的结点的第i + 1(0位置为使用)个位置
void Insert(BTree *q,int i,int key,BTree ap);
//在M阶B树T上,在q所指向的节点第i与i + 1的中间插入key
//若引起结点过大,则沿双亲链进行必要的结点分裂调整,使T仍是m阶B树
void InsertBTree(BTree *T,int key,BTree q,int i);
//将结点q分裂成两个结点,前一半保留,后一半移入新生结点ap
void Split(BTree *q,BTree *ap);
//生成新的根结点T,原T和ap为子树指针
void NewRoot(BTree *T,int key,BTree ap);
//打印出当前结点c的第i个位置的key
void print(BTNode c,int i);
#endif //BTREE_H
实现文件 :BTree.cpp
#include "BTree.h"
#include <stdlib.h>
#include <stdio.h>
//在p->node[1]....p->node[keynum]中查找k所处的位置p->node[i].key <= k < p->node[i+1].key
int Search(BTree p,int k)
{
int i = 0;
int j;
for(j = 1;j <= p->keynum;++j)
if(k >= p->node[j].key) //如果k大于p所指向的结点的第j个位置的关键字,记录下j
i = j;
return i;
}
//在M阶B树T上查找关键字K,返回结果Result
//查找成功,tag = 1,pt指向包函关键字K的结点,i为K在结点中的位置
//查找失败,tag = 0,pt指向K应插入的结点,i...i+1之间插入K
Result SearchBTree(BTree T,int k)
{
Result r; //查找的结果
bool found = false; //是否查找到的标志,初始化为未查找到
int i = 0; //用于记录位置,如查找成功则是k所在结点的第i个位置,
//查找失败则是k应该插入的结点的第i个位置
BTree p = T; //初始化为待查找的结点
BTree q = NULL; //记录父结点,初始化为NULL
while(p && !found) //待查找的结点不为NULL,且未找到进行循环
{
i = Search(p,k); //进行查找
if(i > 0 && p->node[i].key == k) //如果查找成功
found = true;
else
{
q = p; //记录下当前结点,此结点是p->node[i].ptr所指结点的父结点
p = p->node[i].ptr; //p赋值为它的子树,继续进行循环
}
}
r.i = i; //如查找成功则是k所在结点的第i个位置
//查找失败则是k应该插入的结点的第i个位置
if(found) //如果查找成功
{
r.pt = p; //记录下所在的结点的指针
r.tag = 1; //标记为查找成功
}
else{
r.pt = q; //记录下要插入的结点
r.tag = 0; //标记为查找不成功
}
return r;
}
//将key插入到*q所指向的结点的第i + 1个位置
void Insert(BTree *q,int i,int key,BTree ap)
{
int j;
for(j = (*q)->keynum;j > i;--j) //静态数组的插入,第i个位置之后的所有元素向后移一位
(*q)->node[j + 1] = (*q)->node[j];
(*q)->node[i + 1].key = key;
(*q)->node[i + 1].ptr = ap;
(*q)->node[i + 1].recptr = key;
(*q)->keynum++;
}
//在M阶B树T上,在q所指向的节点第i与i + 1的中间插入key
//若引起结点过大,则沿双亲链进行必要的结点分裂调整,使T仍是m阶B树
void InsertBTree(BTree *T,int key,BTree q,int i)
{
BTree ap = NULL;
int s;
int rx = key; //如果进行分裂,rx记录的是需要插入父结点的值
bool finished = false; //记录插入是否完成,初始化为未完成
while(q && !finished) //要插入的结点不为NULL,且插入未完成,进行循环
{
Insert(&q,i,rx,ap);
if(q->keynum < M) //插入完成
finished = true;
else{ //超过BTree的阶,进行分裂
s = (M + 1) / 2;
rx = q->node[s].recptr;
Split(&q,&ap);
q = q->parent;
if(q)
i = Search(q,key); //查找key应该在父结点中插入的位置,在该位置插入rx
}
}
if(!finished) //如果树是空树或已经分裂到根结点
NewRoot(T,rx,ap); //生成新结点原来的T 和 ap做为子树
}
//将结点q分裂成两个结点,前一半保留,后一半移入新生结点ap
void Split(BTree *q,BTree *ap)
{
*ap = (BTree)malloc(sizeof(BTNode));
int s = (M + 1) / 2;
(*ap)->node[0].ptr = (*q)->node[s].ptr;
for(int i = s + 1;i <= M;++i) //将后一半移入新生结点ap
{
(*ap)->node[i - s] = (*q)->node[i];
if((*ap)->node[i - s].ptr)
(*ap)->node[i - s].ptr->parent = *ap;
}
(*ap)->parent = (*q)->parent;
(*ap)->keynum = M - s;
(*q)->keynum = s - 1; //q的前一半保留,修改keynum
}
//生成新的根结点T,原T和ap为子树指针
void NewRoot(BTree *T,int key,BTree ap)
{
BTree temp = (BTree)malloc(sizeof(BTNode)); //新结点
temp->node[0].ptr = *T;
*T = temp;
if((*T)->node[0].ptr)
(*T)->node[0].ptr->parent = *T;
(*T)->parent = NULL;
(*T)->keynum = 1;
(*T)->node[1].key = key;
(*T)->node[1].ptr = ap;
(*T)->node[1].recptr = key;
if((*T)->node[1].ptr)
(*T)->node[1].ptr->parent = (*T);
}
//打印出当前结点c的第i个位置的key
void print(BTNode c,int i)
{
printf("(%d)\n",c.node[i].key);
}
测试文件:main.cpp
#include "BTree.h"
#include <stdio.h>
int main()
{
int a[N] = {11,5,15,18,17,22,59,16,29,1,68,55,99,13,19,62,57};
Result r;
BTree T = NULL;
for(int i = 0;i < N;++i)
{
r = SearchBTree(T,a[i]);
if(!r.tag)
InsertBTree(&T,a[i],r.pt,r.i);
}
int found;
printf("\n请输入要查找的数字:\n");
scanf("%d",&found);
r = SearchBTree(T,found);
if(r.tag)
print(*(r.pt),r.i);
else
printf("未找到\n");
return 0;
}