1.设计并实现B-Trees数据结构,包含其上的基本操作,如节点的插入和删除等。
2.实现在B-trees树上的查找操作。
3.设计良好的运行界面,能够实现重复的操作。
1.3开发环境
开发系统:
Windows系统,处理器要求最低奔腾处理器,内存32m,建议在i5处理器,128m内存配置下调试。
编译集成软件:
Devc++开发软件。
Devc++是一个强大的C/C++软件开发工具,操作简单,使用非常广泛,称为很多程序员的首选开发工具。
2概要设计
2.1功能模块划分
主函数即main()函数,主要实现B-Trees的建立,建立一棵满足要求的4节B-Trres树。
菜单介绍函数即meau()函数,主要包括介绍各个功能的实现途径,并给操作者提供个操作界面。
插入元素函数即insertbtree(b)函数,主要有用户通过界面输入要插入的元素,首先判断要插入的元素是否已在B-Trees中,若不在则插入之。
删除函数即deletetree(b)函数,首先判断要删除的元素是否在B-Trees中若在该B-Trees中则删除。
查找函数即searchbtree(b)函数,由用户通过界面输入一个元素,查找该元素是否在该B-Trees中,若在就输出它在节点的位置。
图2.1主函数流程图
2.2系统流程图
B-树的主程序流程如图2.2所示
图2.2主程序流程图
B-树的主程序流程如图2.3所示
图2.3主程序流程图
3详细设计
3.1数据结构
B-树的数据类型:
typedefstructBTNode
{
intkeynum;//结点中关键字的个数,即结点的大小
structBTNode*parent;//指向双亲指针
intkey[m+1];//关键字向量
structBTNode*ptr[m+1];//子树指针向量
}BTNode
3.2模块设计
B-树插入新元素模块如图3.2所示。
图3.2B-树插入元素函数流程图
B-树删除元素模块如图3.3所示。
图3.3B-树删除元素函数流程图
B-树查找模块如图3.4所示。
图3.4B-树查找元素模块流程图
B-树查找模块如图3.4所示。
图3.5B-树查找元素模块流程图
4测试
4.1测试数据
图表4-1
序号
数据内容
说明
显示截图
1
3
查找,要查元素在B-树中
图4.2
2
5
查找,要查元素不在B-树中
图4.3
3
32
插入,插入元素不在B树中
图4.4
4
42
插入,插入元素在B-树中
图4.5
5
61
删除,删除元素在B-树中
图4.6
6
51
删除,删除元素不在B-树中
图4.7
4.2测试结果
界面主菜单运行结果如图4.1所示。
图4.1主界面运行
查询B-树中元素运行结果分两种可能一是要查元素在B-树中,另一种是不在。
要查元素在B-树中的运行结果如图4.2所示。
图4.2查找B-树已有元素
要查不在元素在B-树中的运行结果如图4.3所示。
图4.3查找B-树中没有元素
插入B-树中元素运行结果分两种可能一是要查元素在B-树中,另一种是不在。
要插入的元素在B-树中的运行结果如图4.4所示。
图4.4插入B-树已有元素
要插入的元素不在B-树中的运行结果如图4.5所示。
图4.5插入B-树中没有元素
插入B-树中元素运行结果分两种可能一是要查元素在B-树中,另一种是不在。
要删除的元素在B-树中的运行结果如图4.6所示。
图4.6删除B-树中已有元素
要删除的元素不在B-树中的运行结果如图4.7所示。
图4.7删除B-树中没有元素
退出B-树中元素的运行结果如图4.8所示。
图4.8退出运行主界面
5总结
历时两周的课程设计终于结束了,对于课程设计:
首先,关于程序方面,我发现即使对设计思路有了眉目,知道了所要用到的B-树的一些知识,但是要把这些写成函数代码,其实还是一件非常不容易的事情。
再加上要完善设计思路,构造整个程序框架在内,都是一件工作量非常大的工作。
幸好,有很多资料可以在网路上搜到。
所以课程设计的第一天,我们搜集了很多关于B-树的资料,包括几种不同思路的程序代码,以及程序流程。
然后我们的工作就变成:
尽量看懂并整理这些代码,然后再其基础上筛选需要的功能,按照自己的意愿来修改与完善。
在操作界面的人性化上,我倒尽可能的做得很完善,无论从美观角度还是方便清楚操作,都实行了非常人性化的方式。
因为通常清楚程序的人,知道怎么操作以及该输入什么,而不清楚的人却有很大可能在细节方面输入错误导致程序运行失败,或是根本不知道应该怎么输入。
所以,尽可能的人性化的设计是非常有必要的,让不懂程序的人也可以正确的操作运行。
在调试程序的过程中,遇到了许多常识性的问题,通过不断的调试、改进,最终使程序能够运行,并且得到正确的运行结果。
在这个过程中,能够不断地发现问题,并且自己独立的去解决多遇到的问题,这是课程设计过程中所不可缺少的精神。
最后,做再次一下总结。
程序方面仍有为解决的问题,希望即便课设之后也可以努力将问题解决掉。
然后B-树的算法中,有些知道怎么做却很难清楚回答出来的问题,希望可以再好好的查找一下相关资料,将知识系统化、理论化、规范化。
参考文献
[1]顾泽元,刘文强编.数据结构.北京:
北京航空航天大学出版社,2011年.
[2]李素若,陈万华,游明坤编.数据结构(C语言描述),中国水利水电出版社,2014年.
[3]李素若,陈万华,游明坤编.数据结构习题解答及上机指导,中国水利水电出版社,2014年.
[4]谭浩强编.C语言设计.清华大学出版社,2011年.
附录源程序代码
#include
#include
#include
#definem4//B-树的阶,设定为4
#definemax32767
typedefstructBTNode
{
intkeynum;//结点中关键字的个数,即结点的大小
structBTNode*parent;//指向双亲指针
intkey[m+1];//关键字向量
structBTNode*ptr[m+1];//子树指针向量
}BTNode,*BTree;//定义B-树的节点结构
intdata[20]={3,24,45,27,53,90,50,61,70,100,12,37,85,105,108,113,121,124,138,135};
BTreeT,R,R1;
intrag;
BTreesearchtree(intk)//查找建树时要插入元素的位置
{
intj;
BTreep1,q1;
p1=T;
while(p1)
{
for(j=1;jif(p1->key[j]>k)
break;
q1=p1;
p1=p1->ptr[j-1];
}
rag=j-1;
returnq1;
}
voidsearch(BTreep2,inta)
{
intj;
for(j=1;jif(p2->key[j]>a)
break;
rag=j-1;
}
voidzimeau()//介绍菜单
{
printf("\t\t\n");
printf("\t\t菜单简介\n");
printf("\t\t\n");
printf("\t\t1.查询结点信息\n");
printf("\t\t2.插入新的结点\n");
printf("\t\t3.删除结点\n");
printf("\t\t4.退出\n");
printf("\t\t\n");
}
intsearchbtree(intk)//查询要查元素在树中,若树中有该元素则打印否则打印说明无
{
inti,found=0;
BTreep;
p=T;
while((!
found)&&(p->ptr[0]!
=NULL))
{
for(i=1;iif(k<=p->key[i])
break;
if(p->key[i]==k)
found=1;
else
p=p->ptr[i-1];
}
if(p->ptr[0]==NULL)
for(i=1;iif(k<=p->key[i])
break;
if(p->key[i]==k)
found=1;
if(found==0)
printf("\t\t此元素不在该B-树中\n");
else
{
printf("\t\t此元素元素在该B-树中\n");
printf("\t\t该元素是B-树中结点的第%d元素\n",i);
}
returnfound;
}
voidinsertbtree(intx)//插入元素函数
{
intj,finished,s;
BTreeq,p;
finished=0;
q=searchtree(x);//查找要插入元素在B-树中的位置
while(!
finished)
{
if(q->keynum==0)//当要插入的元素所在结点是根节点,且为新申请的根结点
{
q->ptr[0]=p;q->ptr[1]=R;q->key[1]=x;
q->keynum++;p->parent=q;R->parent=q;
}
elseif((q->keynum!
=0)&&(q->ptr[0]!
=NULL))//当要插入的元素所在结点是中间的结点x
{
for(j=3;j>rag;j--)
{
q->key[j+1]=q->key[j];q->ptr[j+1]=q->ptr[j];
}
q->ptr[j+1]=R;R->parent=q;q->key[j+1]=x;q->keynum++;
}
else//当插入的元素所在结点是最下层的结点时
{
for(j=3;j>rag;j--)
q->key[j+1]=q->key[j];
q->key[j+1]=x;q->keynum++;
}
finished=0;
if(q->keynumfinished=1;
else//当插入新的结点后,结点的关键字数不小于m时将结点分裂
{
s=m/2+1;x=q->key[s];q->key[s]=max;q->keynum=s-1;
R=(BTNode*)malloc(sizeof(BTNode));//新申请一个结点来存放分裂的另一部分数据
R->key[1]=q->key[s+1];
for(j=2;j<=m;j++)
{
R->key[j]=max;R->ptr[j]=NULL;
}
R->ptr[0]=q->ptr[s];R->ptr[1]=q->ptr[s+1];
R->keynum=1;q->key[s+1]=max;p=q;q=q->parent;
if(!
q)
{
R1=(BTNode*)malloc(sizeof(BTNode));//新申请一个节点作为根节点
T=q=R1;q->keynum=0;q->parent=NULL;
for(j=1;j<=m;j++)
q->key[j]=max;
for(j=0;j<=m;j++)
q->ptr[j]=NULL;
}
else
search(q,x);//在一个结点中查找要插入元素的位置
}
}
}
voiddeletetree1(BTreeq,intj)//当要删除的节点是终端结点,j是要删除元素是节点的地几个元素
{
inti,h;
BTreep,q0,q1;
p=q->parent;
for(h=0;hif(p->ptr[h]==q)
break;
if(h==0)
q1=p->ptr[h+1];
else
{
q0=p->ptr[h-1];q1=p->ptr[h+1];
}
if(q->keynum>=m/2)//当节点的数目不小于m/2
for(i=j;iq->key[i]=q->key[i+1];
else
if((q->keynumkeynum>=2||q1->keynum>=2))//当结点的数目少于m/2但其左兄弟或右兄弟的结点数目大于时
{
if(q1->keynum>=m/2)//右兄弟时
{
q->key[j]=p->key[h];p->key[h]=q1->key[0];
for(i=0;iq1->key[i]=q1->key[i+1];
q1->keynum--;
}
else//左兄弟时
{
q->key[j]=p->key[h];p->key[h]=q0->key[q0->keynum];
q0->key[q0->keynum]=q0->key[q0->keynum+1];q0->keynum--;
}
}
else//当结点的数目少于m/2且其左兄弟和右兄弟的结点数目小于时
{
if(h==0)//当该节点只有有兄弟时
{
q->key[1]=p->key[1];q->key[2]=q1->key[1];q->keynum=2;free(q1);
for(i=1;i{
p->key[i]=p->key[i+1];p->key[i]=p->key[i+1];
}
p->keynum--;
}
else//当该节点有左兄弟时
{
q->key[1]=p->key[h];q->key[2]=q0->key[1];q->keynum=2;free(q0);
for(i=1;i{
p->key[i]=p->key[i+1];
p->ptr[i]=p->ptr[i+1];
}
p->keynum--;
}
}
}
voiddeletetree2(BTreeq,intj)//要插入节点是非终端结点
{
BTreep;
p=q;
while(q->ptr[0])//找终端结点
{
q=q->ptr[j];
if(q->ptr[0]!
=NULL)
q=q->ptr[0];
}
q=q->parent;p->key[j]=q->key[1];
deletetree1(q,1);
}
voiddeletetree(intk)
{
inti,found=0;
BTreep;
p=T;
while((!
found)&&(p->ptr[0]!
=NULL))//找到要插入节点的位置
{
for(i=1;iif(k<=p->key[i])
break;
if(p->key[i]==k)
found=1;
else
p=p->ptr[i-1];
}
if(p->ptr[0]==NULL)
for(i=1;iif(k<=p->key[i])//找到要插入节点的位置
break;
if(p->ptr[0]==NULL)
deletetree1(p,i);//当要删除元素是终端结点
else
deletetree2(p,i);//当插入节点不是终端结点
}
intsearchbtree1(intk)//查询要删除元素是否在树中
{
inti,found=0;
BTreep;
p=T;
while((!
found)&&(p->ptr[0]!
=NULL))
{
for(i=1;iif(k<=p->key[i])
break;
if(p->key[i]==k)
found=1;
else
p=p->ptr[i-1];
}
if(p->ptr[0]==NULL)
for(i=1;iif(k<=p->key[i])
break;
if(p->key[i]==k)
found=1;//返回值,1代表该元素在B-树中可以删除否则无法删除
returnfound;
}
intrumeau()//提供给读者自己的选择
{
intc;
printf("\t\t\t\t请输入您的选择:
");
scanf("%d",&c);
returnc;
}
voidmeau()//菜单选项函数
{
inta,b,rate;
printf("\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3);
do{
zimeau();
printf("\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3);
a=rumeau();//子菜单
switch(a)
{
case1:
system("cls");
printf("\t\t请输入要查找的元素:
");
scanf("%d",&b);
rate=searchbtree(b);//在B-树中查找元素函数
break;
case2:
system("cls");
printf("\t\t请输入要插入的元素:
");
scanf("%d",&b);
rate=searchbtree(b);//查询要插入的元素是否在该B-树中
if(rate==0)
{
printf("\t\t该元素不在此B-树中,故可插入之");
insertbtree(b);//插入新元素函数
}
else
printf("\t\t该元素已在B-树中,不需要再插入\n");
break;
case3:
system("cls");
printf("\t\t请输入要删除的元素:
");
scanf("%d",&b);
rate=searchbtree1(b);
if(rate==0)
printf("\t\t由于该元素不在此B-树中,故无法删除\n");
else
{
printf("\t\t该元素在此B-树中,可删除\n");
deletetree(b);//删除B-树中的元素调用函数
}
break;
}
}while(a!
=4);
}
voidmain()
{
intx,i,finished,s,j;
BTreeq,p;
system("color1B");//背景颜色显示函数
T=(BTNode*)malloc(sizeof(BTNode));T->keynum=0;
for(i=0;i<3;i++)
{
T->key[i+1]=data[i];T->keynum++;
}
T->key[4]=max;
for(i=0;i<5;i++)
T->ptr[i]=NULL;
T->parent=NULL;
for(i=3;i<20;i++)
{
x=data[i];finished=0;q=searchtree(x);//查找要插入元素在B-树中的位置
while(!
finished)
{
if(q->keynum==0)//当要插入的元素所在结点是根节点,且为新申请的根结点
{
q->ptr[0]=p;q->ptr[1]=R;
q->key[1]=x;q->keynum++;p->parent=q;R->parent=q;
}
else
if((q->keynum!
=0)&&(q->ptr[0]!
=NULL))//当要插入的元素所在结点是中间的结点x
{
for(j=3;j>rag;j--)
{q->key[j+1]=q->key[j];q->ptr[j+1]=q->ptr[j];}
q->ptr[j+1]=R;R->parent=q;q->key[j+1]=x;q->keynum++;
}
else//当插入的元素所在结点是最下层的结点时
{
for(j=3;j>rag;j--)
q->key[j+1]=q->key[j];
q->key[j+1]=x;q->keynum++;
}
finished=0;
if(q->keynumfinished=1;
else//当插入新的结点后,结点的关键字数不小于m时将结点分裂
{
s=m/2+1;x=q->key[s];q->key[s]=max;q->keynum=s-1;
R=(BTNode*)malloc(sizeof(BTNode));//新申请一个结点来存放分裂的另一部