C语言-B树(B-树)的完整实现

B树的定义
B树是一种平衡的多路查找树。
一颗m阶B树,或为空树,或为满足下列特性的m叉树。
(1)树中每个结点最多含有m棵子树;
(2)若根结点不是叶子结点,则至少有两颗子树;
(3)除根之外的所有非终端结点至少有[m/2];
(4)每个非终端结点中包含信息:(n,A0,K1,A1,K2,A2,…,Kn,An)。其中
①Ki(1≤i≤n)为关键字,且关键字按升序排序。
②指针Ai(0≤i≤n)指向子树的根结点。
③关键字的个数n必须满足:[m/2]-1≤n≤m-1
(5)所有的叶子结点都出现在同一层次上,并且不带信息(可以看作是外部节点或查找失败的结点,实际上这些结点不存在,指向这些结点的指针为空)

编程环境与配置
IDE:Dev-C++ 5.11
编程语言:C

程序结构图
这里写图片描述
B树的抽象数据类型定义

ADT BTree{
数据对象:D是具有相同特性的数据元素的集合
数据关系:R1={<ai-1,ai>|ai-1,ai∈D,i=2,...,n}
              R2={<ptr[i-1],ptr[i]>|i=1...,n}
  约定a1|key[1]为关键字数组头,an|key[p-<keynum]为关键字数组尾
  约定ptr[i]为结点的第i个子树
基本操作:
InitBTree(t)
初始条件:B树已定义
操作结果:初始化B树
SearchBTNode(BTNode *p,KeyType k)
初始条件:结点p已存在
操作结果:在结点p中查找关键字k的插入位置i 
Result SearchBTree(BTree t,KeyType k)
初始条件:B树已存在
操作结果:在B树查找关键字k的插入位置,返回查找结果
InsertBTNode(BTNode *&p,int i,KeyType k,BTNode *q)
初始条件:结点p和结点q已存在,0<i<p->keynum
操作结果:将关键字k和结点q分别插入到p->key[i+1]和p->ptr[i+1]中
SplitBTNode(BTNode *&p,BTNode *&q)
初始条件:结点p和结点q已存在
操作结果:将结点p分裂成两个结点,前一半保留,后一半移入结点q
NewRoot(BTNode *&t,KeyType k,BTNode *p,BTNode *q)
初始条件:结点t,p,q已存在
操作结果:生成新的根结点t,原p和q为子树指针
InsertBTree(BTree &t,int i,KeyType k,BTNode *p)
初始条件:结点p和结点t已存在,0<i<p->keynum
操作结果:在B树t中插入关键字k
Remove(BTNode *p,int i)
初始条件:结点p已存在,0<i<p->keynum
操作结果:p结点删除key[i]和它的孩子指针ptr[i]
Substitution(BTNode *p,int i)
初始条件:结点p已存在,0<i<p->keynum
操作结果:查找替代值
MoveRight(BTNode *p,int i)
初始条件:结点p已存在,0<i<p->keynum
操作结果:结点调整右移操作
MoveLeft(BTNode *p,int i)
初始条件:结点p已存在,0<i<p->keynum
操作结果:结点调整左移操作
Combine(BTNode *p,int i)
初始条件:结点p已存在,0<i<p->keynum
操作结果:结点调整合并操作
AdjustBTree(BTNode *p,int i)
初始条件:结点p已存在,0<i<p->keynum
操作结果:B树调整操作
BTNodeDelete(BTNode *p,KeyType k)
初始条件:结点p已存在
操作结果:在结点p中删除关键字k
BTreeDelete(BTree &t,KeyType k)
初始条件:B树t已存在
操作结果:在B树t中删除关键字k
DestroyBTree(BTree &t)
初始条件:B树t已存在
操作结果:递归释放B树
PrintBTree(BTree t)
初始条件:B树t已存在
操作结果:遍历打印B树
}ADT BTree

头文件
定义了需要用到的数据类型,结构体类型,以及所有函数接口;

//==========ADT BTree的表示与实现==========
#ifndef _BTREE_H
#define _BTREE_H
#define MAXM 10                 //定义B树的最大的阶数

const int m=4;                      //设定B树的阶数 
const int Max=m-1;                  //结点的最大关键字数量 
const int Min=(m-1)/2;              //结点的最小关键字数量 
typedef int KeyType;                //KeyType为关键字类型

//===============B树存储结构==============
typedef struct node{                //B树和B树结点类型 
    int keynum;                 //结点关键字个数
    KeyType key[MAXM];              //关键字数组,key[0]不使用 
    struct node *parent;            //双亲结点指针
    struct node *ptr[MAXM];         //孩子结点指针数组 
}BTNode,*BTree;

typedef struct{                     //B树查找结果类型 
    BTNode *pt;                 //指向找到的结点
    int i;                          //在结点中的关键字位置; 
    int tag;                        //查找成功与否标志
}Result;

typedef struct LNode{               //链表和链表结点类型 
    BTree data;                     //数据域
    struct LNode *next;             //指针域
}LNode, *LinkList;

typedef enum status{               //枚举类型(依次递增) 
    TRUE,
    FALSE,
    OK,
    ERROR,
    OVERFLOW,
    EMPTY
}Status;

//============基本操作的函数原型声明=============
Status InitBTree(BTree &t);
//初始化B树 
int SearchBTNode(BTNode *p,KeyType k);                          
//在结点p中查找关键字k的插入位置i
Result SearchBTree(BTree t,KeyType k);                          
/*在树t上查找关键字k,返回结果(pt,i,tag)。若查找成功,则特征值
tag=1,关键字k是指针pt所指结点中第i个关键字;否则特征值tag=0,
关键字k的插入位置为pt结点的第i个*/
void InsertBTNode(BTNode *&p,int i,KeyType k,BTNode *q);        
//将关键字k和结点q分别插入到p->key[i+1]和p->ptr[i+1]中
void SplitBTNode(BTNode *&p,BTNode *&q);                        
//将结点p分裂成两个结点,前一半保留,后一半移入结点q
void NewRoot(BTNode *&t,KeyType k,BTNode *p,BTNode *q);         
//生成新的根结点t,原结点p和结点q为子树指针
void InsertBTree(BTree &t,int i,KeyType k,BTNode *p);           
/*在树t上结点q的key[i]与key[i+1]之间插入关键字k。若引起
结点过大,则沿双亲链进行必要的结点分裂调整,使t仍是B树*/
void Remove(BTNode *p,int i);                                   
//从p结点删除key[i]和它的孩子指针ptr[i]
void Substitution(BTNode *p,int i);                             
//查找被删关键字p->key[i](在非叶子结点中)的替代叶子结点(右子树中值最小的关键字) 
void MoveRight(BTNode *p,int i);                               
/*将双亲结点p中的最后一个关键字移入右结点q中
将左结点aq中的最后一个关键字移入双亲结点p中*/
void MoveLeft(BTNode *p,int i);
/*将双亲结点p中的第一个关键字移入结点aq中,
将结点q中的第一个关键字移入双亲结点p中*/
void Combine(BTNode *p,int i);                                  
/*将双亲结点p、右结点q合并入左结点aq,
并调整双亲结点p中的剩余关键字的位置*/                                         
void AdjustBTree(BTNode *p,int i);                              
//删除结点p中的第i个关键字后,调整B树                                        
int FindBTNode(BTNode *p,KeyType k,int &i);                     
//反映是否在结点p中是否查找到关键字k 
int BTNodeDelete(BTNode *p,KeyType k);                          
//在结点p中查找并删除关键字k
void BTreeDelete(BTree &t,KeyType k);                           
//构建删除框架,执行删除操作 
void DestroyBTree(BTree &t);                                    
//递归释放B树
Status InitQueue(LinkList &L);                                  
//初始化队列 
LNode* CreateNode(BTree t);                                     
//新建一个结点 
Status Enqueue(LNode *p,BTree t);                               
//元素q入队列
Status Dequeue(LNode *p,BTNode *&q);                            
//出队列,并以q返回值
Status IfEmpty(LinkList L);                                     
//队列判空 
void DestroyQueue(LinkList L);                                  
//销毁队列 
Status Traverse(BTree t,LinkList L,int newline,int sum);        
//用队列遍历输出B树 
Status PrintBTree(BTree t);                                     
//输出B树 
void Test();                                                    
//测试B树功能函数 
#endif 

B树具体接口实现

2.4.1InitBTree函数
功能:初始化B树
代码实现:
Status InitBTree(BTree &t){
    t=NULL;
    return OK;
}
2.4.2SearchBTNode函数
功能:在结点p中查找关键字k的插入位置i
代码实现:
int SearchBTNode(BTNode *p,KeyType k){
    int i=0;
    for(i=0;i<p->keynum&&p->key[i+1]<=k;i++);
    return i;
}
2.4.3SearchBTree函数
功能:在树t中查找关键字k,返回查找结果类型
代码实现:
Result SearchBTree(BTree t,KeyType k){
    BTNode *p=t,*q=NULL;                            //初始化结点p和结点q,p指向待查结点,q指向p的双亲
    int found_tag=0;                                //设定查找成功与否标志 
    int i=0;                 
    Result r;                                       //设定返回的查找结果 

    while(p!=NULL&&found_tag==0){
        i=SearchBTNode(p,k);                        //在结点p中查找关键字k                   if(i>0&&p->key[i]==k)                       //找到待查关键字
            found_tag=1;                            //查找成功 
        else{                                       //查找失败 
            q=p;                            
            p=p->ptr[i];
        }
    }

    if(found_tag==1){                               //查找成功
        r.pt=p;
        r.i=i;
        r.tag=1;
    }
    else{                                           //查找失败
        r.pt=q;
        r.i=i;
        r.tag=0;
    }
    return r;                                       //返回关键字k的位置(或插入位置)
}
2.4.4InsertBTNode函数
功能:关键字k和结点q分别插入到p->key[i+1]和p->ptr[i+1]中
代码实现:
void InsertBTNode(BTNode *&p,int i,KeyType k,BTNode *q){
    int j;
    for(j=p->keynum;j>i;j--){                       //整体后移空出一个位置
        p->key[j+1]=p->key[j];
        p->ptr[j+1]=p->ptr[j];
    }
    p->key[i+1]=k;
    p->ptr[i+1]=q;
    if(q!=NULL) 
        q->parent=p;
    p->keynum++;
}
2.4.5SplitBTNode函数
功能:将结点p分裂成两个结点,前一半保留,后一半移入结点q
代码实现:
void SplitBTNode(BTNode *&p,BTNode *&q){
    int i;
    int s=(m+1)/2;
    q=(BTNode *)malloc(sizeof(BTNode));             //给结点q分配空间

    q->ptr[0]=p->ptr[s];                            //后一半移入结点q
    for(i=s+1;i<=m;i++){
        q->key[i-s]=p->key[i];
        q->ptr[i-s]=p->ptr[i];
    }
    q->keynum=p->keynum-s;                
    q->parent=p->parent;
    for(i=0;i<=p->keynum-s;i++)                         //修改双亲指针 
        if(q->ptr[i]!=NULL) 
            q->ptr[i]->parent=q;
    p->keynum=s-1;                              //结点p的前一半保留,修改结点p的keynum
}
2.4.6NewRoot函数
功能:生成新的根结点t,原p和q为子树指针
代码实现:
void NewRoot(BTNode *&t,KeyType k,BTNode *p,BTNode *q){
  
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值