1.问题描述:

(1)实现在B-树上的查找,并分析其时间复杂性。

(2)实现B-树的ADT,包括其上的基本操作:结点的加入和删除。

(3)要求B-树结构中的M=3或5,实现其中的一种即可。

(4)实现基本操作的演示。

2.模块划分

(1)初始化B树。

(2)查找操作。

(3)显示操作。

(4)插入操作

(5)删除操作。

(6)销毁操作。

3.代码部分

#ifndef _BTREE_H
#define _BTREE_H
#define MAXM 10                     //定义B树的最大的阶数const int m=5;                      //设定B树的阶数
const int Max=m-1;                  //结点的最大关键字数量
const int Min=(m-1)/2;              //结点的最小关键字数量
typedef int KeyType;                //KeyType为关键字类型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 #include <stdio.h>
#include <malloc.h>
#include <stdlib.h> Status InitBTree(BTree &t){
//初始化B树 t=NULL;return OK;
}int SearchBTNode(BTNode *p,KeyType k){
//在结点p中查找关键字k的插入位置i int i=0;for(i=0;i<p->keynum&&p->key[i+1]<=k;i++);return i;
}Result SearchBTree(BTree t,KeyType k){
/*在树t上查找关键字k,返回结果(pt,i,tag)。若查找成功,则特征值
tag=1,关键字k是指针pt所指结点中第i个关键字;否则特征值tag=0,
关键字k的插入位置为pt结点的第i个*/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,使得p->key[i]<=k<p->key[i+1]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的位置(或插入位置)
}void InsertBTNode(BTNode *&p,int i,KeyType k,BTNode *q){
//将关键字k和结点q分别插入到p->key[i+1]和p->ptr[i+1]中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++;
}void SplitBTNode(BTNode *&p,BTNode *&q){
//将结点p分裂成两个结点,前一半保留,后一半移入结点qint i;int s=(m+1)/2;q=(BTNode *)malloc(sizeof(BTNode));             //给结点q分配空间q->ptr[0]=p->ptr[s];                            //后一半移入结点qfor(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
}void NewRoot(BTNode *&t,KeyType k,BTNode *p,BTNode *q){
//生成新的根结点t,原p和q为子树指针t=(BTNode *)malloc(sizeof(BTNode));             //分配空间 t->keynum=1;t->ptr[0]=p;t->ptr[1]=q;t->key[1]=k;if(p!=NULL)                                     //调整结点p和结点q的双亲指针 p->parent=t;if(q!=NULL) q->parent=t;t->parent=NULL;
}void InsertBTree(BTree &t,int i,KeyType k,BTNode *p){
/*在树t上结点q的key[i]与key[i+1]之间插入关键字k。若引起
结点过大,则沿双亲链进行必要的结点分裂调整,使t仍是B树*/BTNode *q;int finish_tag,newroot_tag,s;                   //设定需要新结点标志和插入完成标志 KeyType x;if(p==NULL)                                     //t是空树NewRoot(t,k,NULL,NULL);                     //生成仅含关键字k的根结点telse{x=k;q=NULL;finish_tag=0;       newroot_tag=0;while(finish_tag==0&&newroot_tag==0){InsertBTNode(p,i,x,q);                  //将关键字x和结点q分别插入到p->key[i+1]和p->ptr[i+1]if (p->keynum<=Max) finish_tag=1;                       //插入完成else{         s=(m+1)/2;SplitBTNode(p,q);                   //分裂结点 x=p->key[s];if(p->parent){                      //查找x的插入位置p=p->parent;i=SearchBTNode(p, x);}else                                //没找到x,需要新结点 newroot_tag=1;}}if(newroot_tag==1)                          //根结点已分裂为结点p和q NewRoot(t,x,p,q);                       //生成新根结点t,p和q为子树指针}
}void Remove(BTNode *p,int i){
//从p结点删除key[i]和它的孩子指针ptr[i]int j;for(j=i+1;j<=p->keynum;j++){                    //前移删除key[i]和ptr[i]p->key[j-1]=p->key[j];p->ptr[j-1]=p->ptr[j];}p->keynum--;
}void Substitution(BTNode *p,int i){
//查找被删关键字p->key[i](在非叶子结点中)的替代叶子结点(右子树中值最小的关键字) BTNode *q;for(q=p->ptr[i];q->ptr[0]!=NULL;q=q->ptr[0]);p->key[i]=q->key[1];                            //复制关键字值
}void MoveRight(BTNode *p,int i){
/*将双亲结点p中的最后一个关键字移入右结点q中
将左结点aq中的最后一个关键字移入双亲结点p中*/ int j;BTNode *q=p->ptr[i];BTNode *aq=p->ptr[i-1];for(j=q->keynum;j>0;j--){                       //将右兄弟q中所有关键字向后移动一位q->key[j+1]=q->key[j];q->ptr[j+1]=q->ptr[j];}q->ptr[1]=q->ptr[0];                            //从双亲结点p移动关键字到右兄弟q中q->key[1]=p->key[i];q->keynum++;p->key[i]=aq->key[aq->keynum];                  //将左兄弟aq中最后一个关键字移动到双亲结点p中p->ptr[i]->ptr[0]=aq->ptr[aq->keynum];aq->keynum--;
}void MoveLeft(BTNode *p,int i){
/*将双亲结点p中的第一个关键字移入左结点aq中,
将右结点q中的第一个关键字移入双亲结点p中*/ int j;BTNode *aq=p->ptr[i-1];BTNode *q=p->ptr[i];aq->keynum++;                                   //把双亲结点p中的关键字移动到左兄弟aq中aq->key[aq->keynum]=p->key[i]; aq->ptr[aq->keynum]=p->ptr[i]->ptr[0];p->key[i]=q->key[1];                            //把右兄弟q中的关键字移动到双亲节点p中q->ptr[0]=q->ptr[1];q->keynum--;for(j=1;j<=aq->keynum;j++){                     //将右兄弟q中所有关键字向前移动一位aq->key[j]=aq->key[j+1];aq->ptr[j]=aq->ptr[j+1];}
}void Combine(BTNode *p,int i){
/*将双亲结点p、右结点q合并入左结点aq,
并调整双亲结点p中的剩余关键字的位置*/ int j;BTNode *q=p->ptr[i];                            BTNode *aq=p->ptr[i-1];aq->keynum++;                                  //将双亲结点的关键字p->key[i]插入到左结点aq     aq->key[aq->keynum]=p->key[i];aq->ptr[aq->keynum]=q->ptr[0];for(j=1;j<=q->keynum;j++){                      //将右结点q中的所有关键字插入到左结点aq aq->keynum++;aq->key[aq->keynum]=q->key[j];aq->ptr[aq->keynum]=q->ptr[j];}for(j=i;j<p->keynum;j++){                       //将双亲结点p中的p->key[i]后的所有关键字向前移动一位 p->key[j]=p->key[j+1];p->ptr[j]=p->ptr[j+1];}p->keynum--;                                    //修改双亲结点p的keynum值 free(q);                                        //释放空右结点q的空间
}void AdjustBTree(BTNode *p,int i){
//删除结点p中的第i个关键字后,调整B树if(i==0)                                        //删除的是最左边关键字if(p->ptr[1]->keynum>Min)                   //右结点可以借MoveLeft(p,1);else                                        //右兄弟不够借 Combine(p,1);else if(i==p->keynum)                           //删除的是最右边关键字if(p->ptr[i-1]->keynum>Min)                 //左结点可以借 MoveRight(p,i);else                                        //左结点不够借 Combine(p,i);else if(p->ptr[i-1]->keynum>Min)                //删除关键字在中部且左结点够借 MoveRight(p,i);else if(p->ptr[i+1]->keynum>Min)                //删除关键字在中部且右结点够借 MoveLeft(p,i+1);else                                            //删除关键字在中部且左右结点都不够借Combine(p,i);
}int FindBTNode(BTNode *p,KeyType k,int &i){
//反映是否在结点p中是否查找到关键字k if(k<p->key[1]){                                //结点p中查找关键字k失败 i=0;return 0;}else{                                           //在p结点中查找i=p->keynum;while(k<p->key[i]&&i>1)i--;if(k==p->key[i])                            //结点p中查找关键字k成功 return 1;}
}int BTNodeDelete(BTNode *p,KeyType k){
//在结点p中查找并删除关键字kint i;int found_tag;                                  //查找标志 if(p==NULL)                                     return 0;else{found_tag=FindBTNode(p,k,i);                //返回查找结果 if(found_tag==1){                           //查找成功 if(p->ptr[i-1]!=NULL){                  //删除的是非叶子结点Substitution(p,i);                  //寻找相邻关键字(右子树中最小的关键字) BTNodeDelete(p->ptr[i],p->key[i]);  //执行删除操作 }elseRemove(p,i);                        //从结点p中位置i处删除关键字}elsefound_tag=BTNodeDelete(p->ptr[i],k);    //沿孩子结点递归查找并删除关键字kif(p->ptr[i]!=NULL)if(p->ptr[i]->keynum<Min)               //删除后关键字个数小于MINAdjustBTree(p,i);                   //调整B树 return found_tag;}
}void BTreeDelete(BTree &t,KeyType k){
//构建删除框架,执行删除操作  BTNode *p;int a=BTNodeDelete(t,k);                        //删除关键字k if(a==0)                                        //查找失败 printf("   关键字%d不在B树中\n",k);else if(t->keynum==0){                          //调整 p=t;t=t->ptr[0];free(p);}
}void DestroyBTree(BTree &t){
//递归释放B树 int i;  BTNode* p=t;  if(p!=NULL){                                    //B树不为空  for(i=0;i<=p->keynum;i++){                  //递归释放每一个结点 DestroyBTree(*&p->ptr[i]);  }  free(p);  }  t=NULL;
}  Status InitQueue(LinkList &L){
//初始化队列 L=(LNode*)malloc(sizeof(LNode));                //分配结点空间 if(L==NULL)                                     //分配失败              return OVERFLOW;L->next=NULL;return OK;
}LNode* CreateNode(BTNode *p){
//新建一个结点 LNode *q;q=(LNode*)malloc(sizeof(LNode));                //分配结点空间if(q!=NULL){                                    //分配成功 q->data=p;q->next=NULL;}return q;
}Status Enqueue(LNode *p,BTNode *q){
//元素q入队列if(p==NULL)                                     return ERROR;                               while(p->next!=NULL)                            //调至队列最后 p=p->next;p->next=CreateNode(q);                          //生成结点让q进入队列 return OK;
}Status Dequeue(LNode *p,BTNode *&q){
//出队列,并以q返回值 LNode *aq;if(p==NULL||p->next==NULL)                      //删除位置不合理 return ERROR; aq=p->next;                                     //修改被删结点aq的指针域p->next=aq->next;                               q=aq->data;free(aq);                                       //释放结点aqreturn OK;
}Status IfEmpty(LinkList L){
//队列判空 if(L==NULL)                                     //队列不存在 return ERROR;if(L->next==NULL)                               //队列为空 return TRUE;return FALSE;                                   //队列非空
}void DestroyQueue(LinkList L){
//销毁队列 LinkList p;if(L!=NULL){p=L;L=L->next;free(p);                                    //逐一释放 DestroyQueue(L);}
}Status Traverse(BTree t,LinkList L,int newline,int sum){
//用队列遍历输出B树 int i;BTree p;if(t!=NULL){printf("  [ ");Enqueue(L,t->ptr[0]);                       //入队         for(i=1;i<=t->keynum;i++){printf(" %d ",t->key[i]);Enqueue(L,t->ptr[i]);                   //子结点入队 }sum+=t->keynum+1;printf("]");if(newline==0){                             //需要另起一行 printf("\n");newline=sum-1;sum=0;}elsenewline--;}if(IfEmpty(L)==FALSE){                         //l不为空 Dequeue(L,p);                              //出队,以p返回 Traverse(p,L,newline,sum);                 //遍历出队结点 }return OK;}Status PrintBTree(BTree t){
//输出B树 LinkList L;if(t==NULL){printf("  B树为空树");return OK;}InitQueue(L);                                   //初始化队列 Traverse(t,L,0,0);                              //利用队列输出 DestroyQueue(L);                                //销毁队列 return OK;
}void Test1(){ system("color 70");  BTNode *t=NULL;Result s;                                       //设定查找结果 int j,n=15;KeyType k;KeyType a[]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};                           printf("创建一棵%d阶B树:\n",m);for(j=0;j<n;j++){                               //逐一插入元素 s=SearchBTree(t,a[j]);if(s.tag==0)InsertBTree(t,s.i,a[j],s.pt);printf("   第%d步,插入元素%d:\n ",j+1,a[j]);PrintBTree(t);}printf("\n");printf("删除操作:\n");                          //删除操作 k=9;                                                        BTreeDelete(t,k);printf("  删除%d:\n ",k);printf("  删除后的B树: \n");PrintBTree(t);printf("\n");k=1;BTreeDelete(t,k);printf("  删除%d:\n ",k);printf("  删除后的B树: \n");PrintBTree(t);printf("\n");printf("  递归释放B树\n");                       //递归释放B树DestroyBTree(t);                                 PrintBTree(t);
} void Test2(){int i,k; system("color 70");BTree t=NULL;  Result s;                                       //设定查找结果 while(1){printf("此时的B树:\n");PrintBTree(t); printf("\n");printf("=============Operation Table=============\n");printf("   1.Init     2.Insert    3.Delete    \n");printf("   4.Destroy  5.Exit      \n");printf("=========================================\n");printf("Enter number to choose operation:_____\b\b\b");scanf("%d",&i);switch(i){case 1:{InitBTree(t);printf("InitBTree successfully.\n");break;}case 2:{printf("Enter number to InsertBTree:_____\b\b\b");scanf("%d",&k);s=SearchBTree(t,k);InsertBTree(t,s.i,k,s.pt);printf("InsertBTree successfully.\n");break;}case 3:{printf("Enter number to DeleteBTree:_____\b\b\b");scanf("%d",&k);BTreeDelete(t,k);printf("\n");printf("DeleteBTree successfully.\n");break;}case 4:{DestroyBTree(t);break;printf("DestroyBTree successfully.\n");}case 5:{exit(-1);               break;}}}
}int main(){Test2();return 0;
}

B树的代码实现和解析相关推荐

  1. JavaScript 语法树与代码转化实践

    JavaScript 语法树与代码转化实践 归纳于笔者的现代 JavaScript 开发:语法基础与实践技巧系列文章中.本文引用的参考资料声明于 JavaScript 学习与实践资料索引中,特别需要声 ...

  2. 数据结构与算法——24. 树的应用:表达式解析树

    文章目录 一.解析树 二.解析树实例:表达式解析 1. 建立表达式解析树 (1)建立表达式解析树的规则 (2)建立表达式解析树的思路 (3)python代码实现 2. 表达式解析树的求值 (1)增加程 ...

  3. 数据结构与算法(Python版)四十八:树的应用(表达式解析)

    树的应用:解析树(语法树) 将树用于表示语言中句子, 可以分析句子的各种语法成分, 对句子的各种成分进行处理 语法分析树主谓宾,定状补 程序设计语言的编译 词法.语法检查从语法树生成目标代码 自然语言 ...

  4. 04.南瓜树低代码平台平台 分析后的感想

    随着企业产品的不断完善,后续将有时间来推进产品转向低代码平台化. 低代码平台不是无代码平台,采用配置的方式完成UI/流程/报表的处理,有业务人员在完成基本的产品框架后,由研发人员完成业务规则代码固化, ...

  5. 【机器学习】树回归和聚类算法解析和应用

    [机器学习]树回归和聚类算法解析和应用 文章目录 1 树回归 2 CART ( Classification And Regression Tree) 分类回归树 3 K-means3.1 合理选择 ...

  6. Android代码入侵原理解析(一)

    Original 2017-05-06 付超红 滴滴安全应急响应中心 2017年初,在滴滴安全沙龙上,滴滴出行安全专家--付超红,针对App的攻与防进行了分享.会后大家对这个议题反响热烈,纷纷求详情求 ...

  7. python中文词云图代码_Python简单实现词云图代码及步骤解析

    一.安装 wordcloud pip install wordcloud 二.加载包.设置路径 import os from wordcloud import WordCloud import mat ...

  8. java解析shell命令_Android中执行java命令的方法及java代码执行并解析shell命令

    这篇文章给大家介绍Android中执行java命令的方法及java代码执行并解析shell命令,需要的朋友一起学习 android中执行java命令的方法大家都晓得吗,下面一段内容给大家带来了具体解析 ...

  9. 如何在vs中创建r树索引代码_线段树详解与实现

    此篇文章用于记录<玩转数据结构>课程的学习笔记 什么是线段树 线段树也被称为区间树,英文名为Segment Tree或者Interval tree,是一种高级的数据结构.这种数据结构更多出 ...

最新文章

  1. Java设计模式(访问者模式-迭代器模式-观察者模式-中介者模式)
  2. UVA 12063 Zeros and Ones
  3. BZOJ3261 最大异或和 解题报告(可持久化Trie树)
  4. 深度学习的非主流应用
  5. 求【javascript设计模式】【高性能网站建设指南】PDF!哪位有给下啊!!!
  6. shell将命令执行的结果赋值给 变量
  7. set、vector与list的构造与排序的耗时测试
  8. SpringCloudStream整合rabbitMq
  9. 我们的高中教育造就了什么?
  10. PHP-电脑搭建服务器
  11. 星巴克——最单纯的SNS应用
  12. 1.MySql驱动的jar包下载
  13. js实现商城特效---鼠标移入图片放大
  14. 三国志战略版:当锋无法破防的司马盾
  15. 6-1 哈夫曼树及哈夫曼编码
  16. 【天下有春】剑气纵横三万里,一剑光寒十九洲
  17. 用开源github,还是咱中国自己的代码托管平台云效?
  18. Enhancing Adversarial Training with Second-Order Statistics of Weights
  19. 【Unity】Post-process后处理之Grain
  20. 大师兄科研网_怎样知道一名研究生有没有科研潜力?

热门文章

  1. linux 内核 虚拟地址,linux内核中的虚拟到物理地址转换
  2. storm显微镜成像原理_STORM 超分辨显微成像 – Prime 95B 应用
  3. 360剑灵洪门崛起服务器维护,剑灵洪门崛起————【维护】9月12日更新维护公告...
  4. 00后女生“云摆摊”两周赚1.5万,实体店转战线上真的能赚钱吗?
  5. c# 隐藏显示 任务栏
  6. MSP430学习总结(二)——GPIO
  7. 小程序客服聊天发送商品详情,快捷发送链接和图文消息,附代码和流程
  8. 文本文件和二进制文件的定义与区别
  9. pytorch测试模型时显存不够的问题
  10. 快吧我的世界盒子java怎么_快吧我的世界盒子怎么解除维护,快吧我的世界盒子解除维护教程...