数据结构课程设计图书管理系统.docx

上传人:b****3 文档编号:3470003 上传时间:2022-11-23 格式:DOCX 页数:32 大小:353.82KB
下载 相关 举报
数据结构课程设计图书管理系统.docx_第1页
第1页 / 共32页
数据结构课程设计图书管理系统.docx_第2页
第2页 / 共32页
数据结构课程设计图书管理系统.docx_第3页
第3页 / 共32页
数据结构课程设计图书管理系统.docx_第4页
第4页 / 共32页
数据结构课程设计图书管理系统.docx_第5页
第5页 / 共32页
点击查看更多>>
下载资源
资源描述

数据结构课程设计图书管理系统.docx

《数据结构课程设计图书管理系统.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计图书管理系统.docx(32页珍藏版)》请在冰豆网上搜索。

数据结构课程设计图书管理系统.docx

数据结构课程设计图书管理系统

一、需求分析

1.图书管理系统中图书管理模块包括图书类型定义:

书号、现存量、总存量,出版时间为整型,定价为浮点型,书名、著者名为字符型,借阅指针、预约指针为读者类型;读者类型定义:

证号为整型、姓名为字符型,另外借阅类型和预约类型组合成其中的共用体类型。

B树(2-3树)类型定义:

关键字个数和关键字数组为整型、另外还有指向双亲的指针、指向子树的指针、记录单元指针;B树查找结果类型定义:

节点指针、关键字序号和查找标志变量为整型。

2.演示程序以用户和计算机的对话方式进行,在计算机终端上显示“提示信息”之后,由用户在键盘上输入演示程序中规定的运算命令,相应的输入数据和运算结果显示在后面。

该演示系统,没有使用文件,全部数据放在内存存放。

四项基本业务都以书号为关键字进行的,采用了B树(2-3树)对书号建立索引,以提高效率。

3.图书管理系统实现功能:

①采编入库:

新书购入,将书号、书名、著者、册数、出版时间添加入图书账目中去,如果这种书在帐中已有,则只将总库存量增加,每新增一个书号则以凹入表的形式显示B树现状。

②清除库存:

实现某本书的全部信息删除操作,每清除一个书号则已以凹入表的形式显示B树现状。

③图书借阅:

如果书的库存量大于零时则执行出借,登记借阅者的图书证号和姓名,系统自动抓取当前借阅时间和计算归还时间。

④图书预约:

如果某书库存为零,则记录预约者姓名和证号,系统自动抓取当前预约时间和取书时间。

⑤图书归还:

注销借阅者信息,并改变该书的现存量。

⑥作者专区:

输入作者名字,系统将查找相应作者全部著作并显示出来。

⑦图书信息:

可以根据书号查阅此书基本信息、借阅信息和预约信息,亦可以查找全部图书基本信息。

二、概要设计

1.抽象数据类型B树定义:

ADTBTree{

数据对象:

D是具有相同特性的数据元素的集合。

各个数据元素均含有类型相同,可惟一标识数据元素的关键字。

数据关系:

数据元素同属于一个集合并且:

一棵m阶的B树,或为空,或为满足下列特性的m叉树:

树中每个结点至多有m棵子树;

若根结点不是叶子结点,则至少有两棵子树;

除根之外的所有非终端结点至少有m/2(取上限)棵子树;

所有的非终端结点包含下列信息数据:

(n,A0,K1,A1,K2,A2,K3,……,Kn,An)

其中:

Ki(i=1,2,……n)为关键字,且Ki

基本操作:

SearchBTree(T,key);

初始条件:

B树T存在,key为和关键字类型相同的给定值。

操作结果:

若T中存在关键字等于key的数据元素,则返回该元素的值或在表中的位置,否则返回“空”。

Insert(T,i,k,P,recptr)

初始条件:

B树q和p存在,i、k是指定变量,recptr指针有效

操作结果:

将k和ap分别插入到q->key[i+1]和q->ptr[i+1],并插入关键字为k的记录recptr

InsertBTree(&T,e);

初始条件:

B树T存在,e为待插入的数据元素。

操作结果:

若T中步存在关键字等于e.key的数据元素,则插入e到T中。

DeleteBTree(&T,key);

初始条件:

B树T存在,key为和关键字类型相同的给定值。

操作结果:

若T中存在其关键字等于key的数据元素,则删除之

BTreeTraverse(BTreeT,Visit)

初始条件:

B树T存在,Visit是对T结点的函数

操作结果:

遍历B树T,对每个结点调用Visit函数

ShowBTree(T);

初始条件:

B树T存在。

操作结果:

以凹入表形式显示B树T。

}ADTBTree

2.系统时间类型定义:

ADTTime{

数据对象:

D={TM是各种整型类型的系统时间格式定义}

数据关系:

数据元素同属一个集合

基本操作:

GetDate(tm&tim)

初始条件:

系统时间运行

操作结果:

获取系统时间,赋予tm变量tim

AddDate(tm&date2,tmdate1,intday)

初始条件:

系统时间date2、date1、day存在

操作结果:

把date1的日期加day天后赋给date2

Earlier(tmdate1,tmdate2)

初始条件:

系统时间date2、date1存在

操作结果:

比较data1与date2日期的迟与早,如果date1早于或等于date2则返回TRUE,否则返回FALSE。

}ADTTime

3.图书管理类型定义:

ADTBTree{

数据对象:

D={ai|ai∈BookType,i=1,2,3,……n,n>=0,其中

每个数据元素ai含有类型相同,可惟一标识数据元素的关键字}

数据关系:

数据元素同属一个集合

基本操作:

InitLibrary(&L);

操作结果:

初始化书库L为空书库。

InsertBook(&L,B,result);

初始条件:

书库L和B已存在,result包含B书在书库中的位置或应该插入的位置。

操作结果:

如果书库中已存在B书,则只将B书的库存量增加,否则插入B书到书库L中。

DeleteBook(&L,&B);

初始条件:

书库L和B存在。

操作结果:

如果书库中存在B书,则从书库中删除B书的信息,并返回OK,否则返回ERROR

BorrowBook(L,&B,R);

初始条件:

书库L存在,B书是书库中的书并且可被读者R借阅。

操作结果:

借出一本B书,记录信息。

ReturnBook(L,&B,R);

初始条件:

书库L存在。

操作结果:

若书库L中有读者R借阅B书的记录,则注销该记录,改变B书现存量,并返回OK,书不存在或无该读者记录则返回ERROR。

BespeakBook(L,&B,R);

初始条件:

书库L存在,B书是书库中的书,R为借阅者。

操作结果:

为读者R预约B书。

ListAuthor(L,author);

初始条件:

书库L存在,author为指定作者姓名

操作结果:

显示author的所有著作。

ShowBookinfo(L,B);

初始条件:

书L存在。

操作结果:

若书库L中存在书B,则显示B书基本信息并返回OK,否则返回ERROR。

PrintAllBooks(L);

初始条件:

书库L存在。

操作结果:

显示所有图书基本信息。

}ADTBTree

3.主程序

intmain()

{

系统界面;

初始化;

for(;;)

{

显示菜单信息;

接受命令;

处理命令;

输出结果;

}

}|

4.本程序有四个调用模块

主程序模块

图书管理模块

↓↓

B树单元模块系统时间模块

三、详细设计

《抽象数据类型B树算法详解》

/**************************抽象数据类型B-树存储定义*************************/

typedefBookNodeRecord;//记录指针为图书结点类型

typedefstructBTNode{

intkeynum;//结点关键字个数

structBTNode*parent;//指向双亲指针

intkey[m+1];//关键字数组,0号单元未用

structBTNode*ptr[m+1];//指向子树指针

Record*recptr[m+1];//记录指针,0号单元未用

}BTNode,*BTree;//B树节点类型和B树类型

typedefstruct{

BTNode*pt;//指向找到的结点或应该插入的结点

inti;//1...m,在结点中关键字序号

inttag;//1表示查找成功,0表示查找失败

}Result;//B树查找结果类型

/****************************************************************************/

/**************************B-树操作定义************************************/

intSearch(BTreep,intk)

/*在B树p中查找关键字k的位置i,使得p->node[i].key≤K<p->node[i+1].key*/

{

inti;

for(i=0;ikeynum&&p->key[i+1]<=k;i++);

returni;

}

ResultSearchBTree(BTreeT,intk)

//在m阶B树T上查找关键字K,返回结果(pt,i,tag)。

若查找成功,则特征值

//tag=1,指针pt所指结点中第i个关键字等于K;否则特征值tag=0,等于K的

//关键字应插入在指针Pt所指结点中第i和第i+1个关键字之间。

{

Resultr;

inti=1;

BTreep=T,q=NULL;//初始化,p指向待查结点,q指向p的双亲

intfound=FALSE;

while(p&&!

found){

i=Search(p,k);//在p->key[1...keynum]中查找

if(i&&p->key[i]==k)found=TRUE;//找到待查关键字

else

{

q=p;

p=p->ptr[i];

}

}

if(found)

{

r.pt=p;

r.i=i;

r.tag=1;

}

else

{

r.pt=q;

r.i=i;

r.tag=0;

}

returnr;

}

voidInsert(BTree&q,inti,intk,BTreeap,Record*recptr)

//将k和ap分别插入到q->key[i+1]和q->ptr[i+1],并插入关键字为k的记录recprt

{

for(intj=q->keynum;j>i;--j)

{//记录、关键字、子树指针后移

q->key[j+1]=q->key[j];

q->ptr[j+1]=q->ptr[j];

q->recptr[j+1]=q->recptr[j];

}

q->key[i+1]=k;//插入记录、关键字、子树指针,关键字个数加1

q->ptr[i+1]=ap;

q->recptr[i+1]=recptr;

q->keynum++;

if(ap)ap->parent=q;//子树ap的父亲指针

}

voidSplit(BTree&q,intn,BTree&ap)

//以n为分界将结点q分裂为两个结点,前一半保留,后一半移入新生结点ap

{

inti;

ap=(BTree)malloc(sizeof(BTNode));//申请新结点ap

ap->ptr[0]=q->ptr[n];

for(i=n+1;i<=m;i++)//n后的关键字、子树指针、记录转移到ap

{

ap->key[i-n]=q->key[i];

ap->ptr[i-n]=q->ptr[i];

ap->recptr[i-n]=q->recptr[i];

}

ap->keynum=q->keynum-n;//计算ap的关键字个数

q->keynum=n-1;//q的关键字个数减少

ap->parent=q->parent;

for(i=0;i<=m-n;i++)

if(ap->ptr[i])ap->ptr[i]->parent=ap;//ap的子树的父亲指针

}

voidNewRoot(BTree&T,BTreep,intk,BTreeap,Record*recptr)

//当插入B树时T为空或根结点分裂为p和ap两个节点,需建立一个根节点空间

//本函数为T申请一块空间,插入p,k,ap和记录rec

{

T=(BTree)malloc(sizeof(BTNode));

T->keynum=1;

T->ptr[0]=p;//插入

T->ptr[1]=ap;

T->key[1]=k;

T->recptr[1]=recptr;

if(p)p->parent=T;//T的子树ap的父亲指针

if(ap)ap->parent=T;

T->parent=NULL;//根节点双亲为NULL

}

intInsertBTree(BTree&T,intk,BTreeq,inti,Record*recptr)

//在m阶B树T上结点*q的key[i]与key[i+1]之间插入关键字K和记录rec。

//若引起结点过大,则沿双亲链进行必要的结点分裂调整,使T仍是m阶B树。

{

BTreeap=NULL;

intfinished=FALSE;//T是空树,生成仅含关键字K的根结点*T

if(!

q)NewRoot(T,NULL,k,NULL,recptr);

else{

while(!

finished)

{

Insert(q,i,k,ap,recptr);/将k和ap插入到q->key[i+1]和q->ptr[i+1]

if(q->keynum

else{

Split(q,(m+1)/2,ap);//分裂结点q

k=q->key[(m+1)/2];

recptr=q->recptr[(m+1)/2];

if(q->parent)

{//在双亲结点*q中查找k的插入位置

q=q->parent;

i=Search(q,k);

}

elsefinished=OVERFLOW;//根节点已分裂为*q和*ap两个结点

}

}

if(finished==OVERFLOW)//根结点已分裂为结点*q和*ap

NewRoot(T,q,k,ap,recptr);//需生成新根结点*T,q和ap为子树指针

}

returnOK;

}

voidTakePlace(BTree&q,int&i)

//*q结点的第i个关键字为k,用q的后继关键字替代q,且令q指向后继所在结点

{

BTreep=q;

q=q->ptr[i];

while(q->ptr[0])q=q->ptr[0];//查找p的后继

p->key[i]=q->key[1];//关键字代替

p->recptr[i]=q->recptr[1];//记录代替

i=1;//代替后应该删除q所指结点的第1个关键字

}

voidDel(BTreeq,inti)

//删除q所指结点第i个关键字及其记录

{

for(;ikeynum;i++)//关键字和记录指针前移

{

q->key[i]=q->key[i+1];

q->recptr[i]=q->recptr[i+1];

}

q->keynum--;//关键字数目减1

}

intBorrow(BTreeq)

//若q的兄弟结点关键字大于(m-1)/2,则从兄弟结点上移最小(或最大)的关键字到双亲结点,

//而将双亲结点中小于(或大于)且紧靠该关键字的关键字下移至q中,并返回OK,否则返回EREOR。

{

inti;

BTreep=q->parent,b;//p指向q的双亲结点

for(i=0;p->ptr[i]!

=q;i++);//查找q在双亲p的子树位置

if(i>=0&&i+1<=p->keynum&&p->ptr[i+1]->keynum>(m-1)/2)

{//若q的右兄弟关键字个数大于(m-1)/2

b=p->ptr[i+1];//b指向右兄弟结点

q->ptr[1]=b->ptr[0];//子树指针也要同步移动

q->key[1]=p->key[i+1];//从父节点借第i+1个关键字

q->recptr[1]=p->recptr[i+1];

p->key[i+1]=b->key[1];//b第一个关键字上移到父节点

p->recptr[i+1]=b->recptr[1];

for(i=1;i<=b->keynum;i++)//b第一个关键字上移,需把剩余记录前移一位

{

b->key[i]=b->key[i+1];

b->recptr[i]=b->recptr[i+1];

b->ptr[i-1]=b->ptr[i];

}

}

elseif(i>0&&p->ptr[i-1]->keynum>(m-1)/2)

{//若q的左兄弟关键字个数大约(m-1)/2

b=p->ptr[i-1];//b指向左兄弟结点

q->ptr[1]=q->ptr[0];

q->ptr[0]=b->ptr[b->keynum];

q->key[1]=p->key[i];//从父节点借第i个关键字

q->recptr[1]=p->recptr[i];

p->key[i]=b->key[b->keynum];//将b最后一个关键字上移到父节点

p->recptr[i]=b->recptr[b->keynum];

}

elsereturnERROR;//无关键字大于(m-1)/2的兄弟

q->keynum++;

b->keynum--;

for(i=0;i<=q->keynum;i++)

if(q->ptr[i])q->ptr[i]->parent=q;//刷新q的子结点的双亲指针

returnOK;

}

voidCombine(BTree&q)

//将q剩余部分和q的父结点的相关关键字合并到q兄弟中,然后释放q,令q指向修改的兄弟

{

inti,j;

BTreep=q->parent,b;//p指向q的父亲

for(i=0;p->ptr[i]!

=q;i++);//插好q在父亲p中的子树位置

if(i==0)//如为0,则需合并为兄弟的第一个关键字

{

b=p->ptr[i+1];

for(j=b->keynum;j>=0;j--)//将b的关键字和记录后移一位

{

b->key[j+1]=b->key[j];

b->recptr[j+1]=b->recptr[j];

b->ptr[j+1]=b->ptr[j];

}

b->ptr[0]=q->ptr[0];//合并

b->key[1]=p->key[1];

b->recptr[1]=p->recptr[1];

}

elseif(i>0)//若q在父亲的子树位置大约0

{//需合并为兄弟b的最后一个关键字

b=p->ptr[i-1];

b->key[b->keynum+1]=p->key[i];//合并

b->recptr[b->keynum+1]=p->recptr[i];

b->ptr[b->keynum+1]=q->ptr[0];

}

if(i==0||i==1)//若i为0或1,需将父节点p关键字前移一位

for(;ikeynum;i++)

{

p->key[i]=p->key[i+1];

p->ptr[i]=p->ptr[i+1];

p->recptr[i]=p->recptr[i+1];

}

p->keynum--;

b->keynum++;

free(q);

q=b;//q指向修改的兄弟结点

for(i=0;i<=b->keynum;i++)

if(b->ptr[i])b->ptr[i]->parent=b;//刷新b的子结点的双亲指针

}

intDeleteBTree(BTree&T,intk)

//在m阶B树T上删除关键字k及其对应记录,并返回OK。

//如T上不存在关键字k,则返回ERROR。

{

intx=k;

BTreeq,b=NULL;

intfinished=FALSE,i=1;

Resultres=SearchBTree(T,k);//在T中查找关键字k

if(res.tag==0)returnERROR;//未搜索到

else

{

q=res.pt;//q指向待删结点

i=res.i;

if(q->ptr[0])TakePlace(q,i);//若q的子树不空,(非底层结点)

//则以其后继代之,且令q指向后继所在结点

Del(q,i);//删除q所指向结点中第i个关键字及记录

if(q->keynum>=(m-1)/2||!

q->parent)//若删除后关键字个数不小于(m-1)/2或q是根

{

finished=TRUE;//删除完成

if(q->keynum==0)

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 动态背景

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1