问题描述:

实现B-树的基本操作。基于序列{4, 9, 0, 1, 8, 6, 3, 5, 2, 7}完成测试。
  (1)创建对应的3阶B-树b,用括号法输出b树。
  (2)从b中分别删除关键字为8和1的节点,用括号法输出删除节点后的b树。

代码如下:

/*
Copyright (c) 2015,烟台大学计算机与控制工程学院
All righs reserved
文件名称:test.cpp
作者: 李哲
完成日期:2015年12月7日
问题描述:B-树的基本操作
程序说明:主函数
*/
#include <stdio.h>
#include <malloc.h>
#define MAXM 10                     //定义B-树的最大的阶数
typedef int KeyType;                //KeyType为关键字类型
typedef struct node                 //B-树结点类型定义
{
int keynum;                     //结点当前拥有的关键字的个数
KeyType key[MAXM];              //key[1..keynum]存放关键字,key[0]不用
struct node *parent;            //双亲结点指针
struct node *ptr[MAXM];         //孩子结点指针数组ptr[0..keynum]
} BTNode;
typedef struct                      //B-树的查找结果类型
{
BTNode *pt;                     //指向找到的结点
int i;                          //1..m,在结点中的关键字序号
int tag;                        //1:查找成功,O:查找失败
}  Result;
int m;                              //m阶B-树,为全局变量
int Max;                            //m阶B-树中每个结点的至多关键字个数,Max=m-1
int Min;                            //m阶B-树中非叶子结点的至少关键字个数,Min=(m-1)/2
int Search(BTNode *p,KeyType k)
{
//在p->key[1..keynum]中查找i,使得p->key[i]<=k<p->key[i+1]
int i=0;
for(i=0; i<p->keynum && p->key[i+1]<=k; i++);
return i;
}
Result SearchBTree(BTNode *t,KeyType k)
{
/*在m阶t树t上查找关键字k,返回结果(pt,i,tag)。若查找成功,则特征值
tag=1,指针pt所指结点中第i个关键字等于k;否则特征值tag=0,等于k的
关键字应插入在指针Pt所指结点中第i和第i+1个关键字之间*/
BTNode *p=t,*q=NULL; //初始化,p指向待查结点,q指向p的双亲
int found=0,i=0;
Result r;
while (p!=NULL && found==0)
{
i=Search(p,k);              //在p->key[1..keynum]中查找i,使得p->key[i]<=k<p->key[i+1]
if (i>0 && p->key[i]==k)    //找到待查关键字
found=1;
else
{
q=p;
p=p->ptr[i];
}
}
r.i=i;
if (found==1)                   //查找成功
{
r.pt=p;
r.tag=1;
}
else                            //查找不成功,返回K的插入位置信息
{
r.pt=q;
r.tag=0;
}
return r;                       //返回k的位置(或插入位置)
}
void Insert(BTNode *&q,int i,KeyType x,BTNode *ap)
{
//将x和ap分别插入到q->key[i+1]和q->ptr[i+1]中
int j;
for(j=q->keynum; j>i; j--)  //空出一个位置
{
q->key[j+1]=q->key[j];
q->ptr[j+1]=q->ptr[j];
}
q->key[i+1]=x;
q->ptr[i+1]=ap;
if (ap!=NULL) ap->parent=q;
q->keynum++;
}
void Split(BTNode *&q,BTNode *&ap)
{
//将结点q分裂成两个结点,前一半保留,后一半移入新生结点ap
int i,s=(m+1)/2;
ap=(BTNode *)malloc(sizeof(BTNode));    //生成新结点*ap
ap->ptr[0]=q->ptr[s];                   //后一半移入ap
for (i=s+1; i<=m; i++)
{
ap->key[i-s]=q->key[i];
ap->ptr[i-s]=q->ptr[i];
if (ap->ptr[i-s]!=NULL)
ap->ptr[i-s]->parent=ap;
}
ap->keynum=q->keynum-s;
ap->parent=q->parent;
for (i=0; i<=q->keynum-s; i++) //修改指向双亲结点的指针
if (ap->ptr[i]!=NULL) ap->ptr[i]->parent = ap;
q->keynum=s-1;                      //q的前一半保留,修改keynum
}
void NewRoot(BTNode *&t,BTNode *p,KeyType x,BTNode *ap)
{
//生成含信息(T,x,ap)的新的根结点*t,原t和ap为子树指针
t=(BTNode *)malloc(sizeof(BTNode));
t->keynum=1;
t->ptr[0]=p;
t->ptr[1]=ap;
t->key[1]=x;
if (p!=NULL) p->parent=t;
if (ap!=NULL) ap->parent=t;
t->parent=NULL;
}
void InsertBTree(BTNode *&t, KeyType k, BTNode *q, int i)
{
/*在m阶t树t上结点*q的key[i]与key[i+1]之间插入关键字k。若引起
结点过大,则沿双亲链进行必要的结点分裂调整,使t仍是m阶t树。*/
BTNode *ap;
int finished,needNewRoot,s;
KeyType x;
if (q==NULL)                        //t是空树(参数q初值为NULL)
NewRoot(t,NULL,k,NULL);         //生成仅含关键字k的根结点*t
else
{
x=k;
ap=NULL;
finished=needNewRoot=0;
while (needNewRoot==0 && finished==0)
{
Insert(q,i,x,ap);               //将x和ap分别插入到q->key[i+1]和q->ptr[i+1]
if (q->keynum<=Max) finished=1; //插入完成
else
{
//分裂结点*q,将q->key[s+1..m],q->ptr[s..m]和q->recptr[s+1..m]移入新结点*ap
s=(m+1)/2;
Split(q,ap);
x=q->key[s];
if (q->parent)              //在双亲结点*q中查找x的插入位置
{
q=q->parent;
i=Search(q, x);
}
else needNewRoot=1;
}
}
if (needNewRoot==1)                 //根结点已分裂为结点*q和*ap
NewRoot(t,q,x,ap);              //生成新根结点*t,q和ap为子树指针
}
}
void DispBTree(BTNode *t)   //以括号表示法输出B-树
{
int i;
if (t!=NULL)
{
printf("[");            //输出当前结点关键字
for (i=1; i<t->keynum; i++)
printf("%d ",t->key[i]);
printf("%d",t->key[i]);
printf("]");
if (t->keynum>0)
{
if (t->ptr[0]!=0) printf("(");  //至少有一个子树时输出"("号
for (i=0; i<t->keynum; i++)     //对每个子树进行递归调用
{
DispBTree(t->ptr[i]);
if (t->ptr[i+1]!=NULL) printf(",");
}
DispBTree(t->ptr[t->keynum]);
if (t->ptr[0]!=0) printf(")");  //至少有一个子树时输出")"号
}
}
}
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 Successor(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)
//把一个关键字移动到右兄弟中
{
int c;
BTNode *t=p->ptr[i];
for (c=t->keynum; c>0; c--) //将右兄弟中所有关键字移动一位
{
t->key[c+1]=t->key[c];
t->ptr[c+1]=t->ptr[c];
}
t->ptr[1]=t->ptr[0];        //从双亲结点移动关键字到右兄弟中
t->keynum++;
t->key[1]=p->key[i];
t=p->ptr[i-1];              //将左兄弟中最后一个关键字移动到双亲结点中
p->key[i]=t->key[t->keynum];
p->ptr[i]->ptr[0]=t->ptr[t->keynum];
t->keynum--;
}
void MoveLeft(BTNode *p,int i)
//把一个关键字移动到左兄弟中
{
int c;
BTNode *t;
t=p->ptr[i-1];              //把双亲结点中的关键字移动到左兄弟中
t->keynum++;
t->key[t->keynum]=p->key[i];
t->ptr[t->keynum]=p->ptr[i]->ptr[0];
t=p->ptr[i];                //把右兄弟中的关键字移动到双亲兄弟中
p->key[i]=t->key[1];
p->ptr[0]=t->ptr[1];
t->keynum--;
for (c=1; c<=t->keynum; c++)    //将右兄弟中所有关键字移动一位
{
t->key[c]=t->key[c+1];
t->ptr[c]=t->ptr[c+1];
}
}
void Combine(BTNode *p,int i)
//将三个结点合并到一个结点中
{
int c;
BTNode *q=p->ptr[i];            //指向右结点,它将被置空和删除
BTNode *l=p->ptr[i-1];
l->keynum++;                    //l指向左结点
l->key[l->keynum]=p->key[i];
l->ptr[l->keynum]=q->ptr[0];
for (c=1; c<=q->keynum; c++)        //插入右结点中的所有关键字
{
l->keynum++;
l->key[l->keynum]=q->key[c];
l->ptr[l->keynum]=q->ptr[c];
}
for (c=i; c<p->keynum; c++)     //删除父结点所有的关键字
{
p->key[c]=p->key[c+1];
p->ptr[c]=p->ptr[c+1];
}
p->keynum--;
free(q);                        //释放空右结点的空间
}
void Restore(BTNode *p,int i)
//关键字删除后,调整B-树,找到一个关键字将其插入到p->ptr[i]中
{
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 SearchNode(KeyType k,BTNode *p,int &i)
//在结点p中找关键字为k的位置i,成功时返回1,否则返回0
{
if (k<p->key[1])    //k小于*p结点的最小关键字时返回0
{
i=0;
return 0;
}
else                //在*p结点中查找
{
i=p->keynum;
while (k<p->key[i] && i>1)
i--;
return(k==p->key[i]);
}
}
int RecDelete(KeyType k,BTNode *p)
//查找并删除关键字k
{
int i;
int found;
if (p==NULL)
return 0;
else
{
if ((found=SearchNode(k,p,i))==1)       //查找关键字k
{
if (p->ptr[i-1]!=NULL)              //若为非叶子结点
{
Successor(p,i);                 //由其后继代替它
RecDelete(p->key[i],p->ptr[i]); //p->key[i]在叶子结点中
}
else
Remove(p,i);                    //从*p结点中位置i处删除关键字
}
else
found=RecDelete(k,p->ptr[i]);       //沿孩子结点递归查找并删除关键字k
if (p->ptr[i]!=NULL)
if (p->ptr[i]->keynum<Min)          //删除后关键字个数小于MIN
Restore(p,i);
return found;
}
}
void DeleteBTree(KeyType k,BTNode *&root)
//从B-树root中删除关键字k,若在一个结点中删除指定的关键字,不再有其他关键字,则删除该结点
{
BTNode *p;              //用于释放一个空的root
if (RecDelete(k,root)==0)
printf("   关键字%d不在B-树中\n",k);
else if (root->keynum==0)
{
p=root;
root=root->ptr[0];
free(p);
}
}
int main()
{
BTNode *t=NULL;
Result s;
int j,n=10;
KeyType a[]= {4,9,0,1,8,6,3,5,2,7},k;
m=3;                                //3阶B-树
Max=m-1;
Min=(m-1)/2;
printf("创建一棵%d阶B-树:\n",m);
for (j=0; j<n; j++)                 //创建一棵3阶B-树t
{
s=SearchBTree(t,a[j]);
if (s.tag==0)
InsertBTree(t,a[j],s.pt,s.i);
printf("   第%d步,插入%d: ",j+1,a[j]);
DispBTree(t);
printf("\n");
}
printf("  结果B-树: ");
DispBTree(t);
printf("\n");
printf("删除操作:\n");
k=8;
DeleteBTree(k,t);
printf("  删除%d: ",k);
printf("B-树: ");
DispBTree(t);
printf("\n");
k=1;
DeleteBTree(k,t);
printf("  删除%d: ",k);
printf("B-树: ");
DispBTree(t);
printf("\n");
return 0;
}

输出结果:

*第十五周*数据结构实践项目三【B-树的基本操作】相关推荐

  1. 第十六周上机实践—项目2—大数据集上排序算法性能的体验

    /* *Copyright(c) 2015,烟台大学计算机学院 *All rights reserved. *文件名称:test.cpp *作者:林莉 *完成日期:2015年12月18日 *版本:v1 ...

  2. 第十二周上机实践项目 项目1-实现复数类中的运算符重载 (2)

    问题及代码: [项目-实现复数类中的运算符重载] (1)请用类的成员函数,定义复数类重载运算符+.-.*./,使之能用于复数的加减乘除 class Complex { public:Complex() ...

  3. 左耳听风 第三十五周

    左耳听风 第三十五周 每周完成一个ARTS: 每周至少做一个 leetcode 的算法题.阅读并点评至少一篇英文技术文章.学习至少一个技术技巧.分享一篇有观点和思考的技术文章.(也就是 Algorit ...

  4. C语言编程>第二十五周 ③ 下列给定程序中,函数fun的功能是:根据输入的三个边长(整型值),判断能否构成三角形;构成的是等边三角形,还是等腰三角形。若能构成等边三角形函数返回3,若能构成……

    例题:下列给定程序中,函数fun的功能是:根据输入的三个边长(整型值),判断能否构成三角形:构成的是等边三角形,还是等腰三角形.若能构成等边三角形函数返回3,若能构成等腰三角形函数返回2,若能构成三角 ...

  5. 信息安全系统设计基础第十五周总结

    信息安全系统设计基础第十五周总结 [内容:链接汇总] 一.每周读书笔记链接汇总 [第一周读书笔记] http://www.cnblogs.com/shadow135211/p/4824555.html ...

  6. 2019年6月6日第十五周体育馆团体预约系统UML软件工程项目日志

    体育馆团体预约系统 UML软件工程项目日志 June,6th ,2019 目录 一. 博客地址 1 二. 客户提交内容 1 三. 项目背景 2 四. 项目范围和前景 2 五. 沟通记录 3 六. 甲方 ...

  7. 第十五周学习周记——微信小程序开发初步

    第十五周学习周记 前言 一.小程序简介 二.小程序代码构成 1. JSON配置 2. WXML模板 3. WXSS样式 4. JS逻辑交互 总结 前言 这一周将开始微信小程序的学习. 一.小程序简介 ...

  8. 学习进度条(第十五周)

    学习进度条(第十五周) 所用时间:15小时左右 代码量:185行 博客量:3篇 收获知识:阅读<梦断代码>体会程序员的精彩经历,学会如何项目总结. 转载于:https://www.cnbl ...

  9. 软件工程进度条-第十五周

    第十五周 所花时间(包括上课) 23 代码量(行) 1200 博客量(篇) 6 了解到的知识点 1.了解ListView的基本用法,并改变焦点触碰事件: 2.理解团队开发后进行软件项目总结的益处: 转 ...

  10. C语言编程>第二十五周 ① 给定程序中,函数fun的功能是:在形参s所指字符串中的每个非数字字符之后插入一个“*”号。

    例题:给定程序中,函数fun的功能是:在形参s所指字符串中的每个非数字字符之后插入一个"*"号. 例如,形参s所指的字符串为:albc45sdtg56f,则执行结果为:a*1b*c ...

最新文章

  1. od结构体大小_od内存断点的探析和检测方法
  2. 3ds Max绘制青花瓷茶壶
  3. vue脚手架创建项目步骤
  4. Java 动态写轮眼 SharinganJPanel (整理)
  5. day18 面向对象
  6. 【HDU - 6441】Find Integer (费马大定理 + 奇偶数列法构造勾股定理)
  7. cobbler get-loaders 通过代理下载
  8. 最佳的MongoDB客户端管理工具
  9. python子进程进行kinit认证_使用kafka-python客户端进行kafka kerberos认证
  10. WinForm小程序系列:注册表阅读器
  11. wifi 2.4GHz和5GHz范围
  12. 【硬核课】最新《图卷积神经网络GCN》2020概述,76页ppt,NTU-Xavier Bresson,纽约大学深度学习课程...
  13. java 人物头像识别
  14. SIGIR 2020最佳论文公布,清华大学揽多个奖项,大三学生摘得最佳短论文奖
  15. 2020数学建模国赛A题解题思路
  16. HaaS云端一体智能语音交互方案
  17. OpenStack组件部署之Placement
  18. python、pandas、Excel、Powerbi中对日期的处理方法
  19. Jlink在ADS下的配置说明及常见问题解决办法
  20. 关于植物大战僵尸如何更改关卡与金币

热门文章

  1. 33款创意的二维码名片设计作品欣赏
  2. 如何解决苹果Mac安装Axure首次打开报错的问题?
  3. 支持MacOS 12.x的虚拟机VMware Fusion Pro for Mac
  4. SyncBird Pro的PhoneCare功能如何使用
  5. Ubuntu通过apt-get安装指定版本和查询软件源有多少个版本
  6. Ubuntu系统多屏幕时 触摸屏如何分屏定位
  7. Flex tree加三状态的Checkbox
  8. FZU 1054 阅读顺序
  9. 宜人贷CTO段念:透明与面向目标是管理理念的核心
  10. Wordpress 错误ERROR: Cookies are blocked or not supported by your browser.