图书管理课程设计报告.docx
《图书管理课程设计报告.docx》由会员分享,可在线阅读,更多相关《图书管理课程设计报告.docx(54页珍藏版)》请在冰豆网上搜索。
图书管理课程设计报告
课程设计题目及要求
10.图书管理(难度3)
【问题描述】
图书管理基本业务活动包括:
对一本书的采编入库、清除库存、借阅和归还等等。
试设计一个图书管理系统,将上述业务活动借助于计算机系统完成。
【基本要求】
〈1〉每种书的登记内容至少包括书号、书名、著者、现存量和总库存量等五项。
〈2〉作为演示系统,不必使用文件,全部数据可以都在内存存放。
但是由于上述四项基本业务活动都是通过书号(即关键字〉进行的,所以要用B树〈24树〉对书号建立索引,以获得高效率。
〈3〉系统应实现的操作及其功能定义如下:
1采编入库z新购入一种书,经分类和确定书号之后登记到图书账目中去。
如果这种书在账中已有,则只将总库存量增加。
②清除库存:
某种书已无保留价值,将它从图书账目中注销。
③借阅:
如果一种书的现存量大于零,则借出一本,登记借阅者的图书证号和归还期限。
④归还z注销对借阅者的登记,改变该书的现存量。
⑤显示:
以凹入表的形式显示B树。
这个操作是为了调试和维护的目的而设置的。
【测试数据】
入库书号:
35,16,18,70,5,50,22,60,13,17,12,45,25,42,15,90,30,7然后清除:
45,90,50,22,42
其余数据自行设计。
由空树开始,每插入删除一个关键字后就显示B树的状态。
【实现提示】
(1)24树的查找算法是基础,入库和清除操作都要调用。
难点在于删除关键字的算法,因而只要算法对2-3树适用就可以了,暂时不必追求高阶B树也适用的删除算法。
(2)每种书的记录可以用动(或静)态链式结构。
借阅登记信息可以链接在相应的那种书的记录之后。
【进一步完成内容】
(l)将一次会话过程(即程序一次运行)中的全部人机对话记入一个日志文件"log"中去。
(2)增加列出某著者全部著作名的操作。
思考如何提高这一操作的效率,参阅教科书12.6.2节。
(3〉增加列出某种书状态的操作。
状态信息除了包括这种书记录的全部信息外还包括最早到期(包括已逾期)的借阅者证号,日期可用整数实现,以求简化。
(4)增加预约借书功能。
完成情况:
基本数据结构设计
算法设计及流程图
输入输出设计
代码规范及注释
数据测试及调试
代码理解与说明
评语
综合评分
第一部分:
引言
数据结构课程设计的主要目的是培养学生综合运用数据结构程序设计课程所学到的知识,编写C程序解决实际问题的能力,以及严谨的工作态度和良好的程序设计习惯。
通过课程设计的训练,学生应该能够了解程序设计的基本开发过程,掌握编写、调试和测试C语言程序的基本技巧,充分理解结构化程序设计的基本方法。
数据结构程序设计的主要任务是要求学生遵循软件开发过程的基本规范,运用结构化程序设计的方法,按照课程设计的题目要求,分析、设计、编写、调试和测试数据结构程序及编写设计报告。
第二部分:
系统功能和原始数据
(1)原始数据
入库书号:
35,16,18,70,5,50,22,60,13,17,12,45,25,42,15,90,30,7然后清除:
45,90,50,22,42
(2)系统功能
1.图书信息录入功能;
2.图书信息浏览功能;
3.按书名查询图书信息;
4.图书信息添加、删除功能;
备注:
图书信息包括:
书的编号、书名、作者名、剩余量、总库存量、借书者信息等。
第三部分:
程序总体设计
(1)数据结构
B-树,顺序表。
#definem5//B-树的阶
#defineM20//借相同书的最大人数
/*************借阅者信息(用单链表方式存储)***********/
structdata//记录借书和还书日期的结构体类型
{
intyear;//记录年
intmonth;//记录月
intday;//记录日
};
typedefstructRe{
charnumber[20];//借阅者编号
structdatabro;//记录读者的借书日期
structdataback;//记录读者的还书日期
}Reader;
/*************书的结构体***********/
typedefstructBook{
unsignedintkey;//书的编号
charbname[20];//书的名称
charwritter[20];//作者姓名
unsignedintleft;//剩余量
unsignedinttotal;//总库存量
Readerreader[M];//借书者记录
}Books;
/*************B-树的存储结构***********/
typedefstructBTNode{
intkeynum;//结点关键子的个数
structBTNode*parent;//指向父结点的指针
Bookskey[m+1];//一个结点中最多存放的书的个数
structBTNode*ptr[m+1];//指向孩子结点的指针
}BTNode,*BTree;
/*************查找结果的存储结构体***********/
typedefstruct{
BTNode*pt;
inti;
inttag;
}Result;
(2)模块划分和层次结构
(3)函数原型清单
/*************欢迎界面*************/
voidprint();//界面
charmenu();//菜单界面
/*************输入书的信息*************/
voidInBookMess(Books&book);//输入书号、书名等
/*************查找关键字在结点的位置*************/
intSearch(BTreep,BooksK);//一个结点中查找元素,返回结点的位置
ResultSearchBTree(BTreeT,BooksK);//查找K书在树的位置并返回结果结构体
voidShowBookMess(Booksbook);//显示一本书的具体信息
/*************插入关键字*************/
voidNewRoot(BTree&T,BTreep,Booksx,BTreeap);//生成一个树新的结点
voidsplit(BTree&q,ints,BTree&ap);//分离节点
voidInsert(BTree&q,inti,Booksx,BTreeap);//一个节点上的插入
intInsertBTree(BTree&T,BooksK);//将书插到B-树上
/*************B-树凹入输出*************/
voidmball(BTreebth,intnum);//凹入输出
/*************删除关键字*************/
voidMoveLeft(BTree&q,inti);//将一个关键词经结点q移到左兄弟中,q为要删关键字结点的双亲结点
voidMoveRight(BTree&q,inti);//将一个关键词经结点q移到右兄弟中,q为要删关键字结点的双亲结点
voidMerge(BTree&q,inti);//合并结点,q为被删关键字结点的双亲结点
voidDeleteBTree(BTree&T);//删除一个关键字
/*************显示书库*************/
voiddisplay(BTreeT);//显示一棵树的所有书的书名
/*************输入书的关键字***********/
voidInBookKey(Books&book);//输入查找书的关键字
/*************借还书*************/
voidborrow(BTreeroot);//借书
voidpayback(BTreeroot);//还书
(4)程序总体框架
intmain()
{
Resultrs;
Booksk;
chart;//输入y或者n
while
(1)
{
charc;
print();
c=menu();//显示菜单
switch(c)//按菜单函数返回值调用各相应函数
{
case'1':
system("cls");
printf("\t------------------录入书信息----------------\n");
InBookMess(k);//输入添加书的内容
InsertBTree(root,k);//将书插入在B-树中
printf("\t------------------录入结束------------------\n");
printf("\nTheBtreeis:
\n");
mball(root,0);//凹入输出
break;
case'2':
system("cls");
DeleteBTree(root);//删除B-树中的一本书
printf("\nTheBtreeis:
\n");
mball(root,0);
break;
case'3':
system("cls");
printf("\t------------------------------全部的书----------------------------\n\n");
display(root);//显示整棵树的书的信息
printf("\t------------------------------显示完毕-----------------------------\n");
break;
case'4':
system("cls");
printf("\t------------------凹入表示法显示----------------\n");
printf("\nTheBtreeis:
\n");
mball(root,0);
break;
case'5':
system("cls");
printf("\t------------------查找书信息----------------\n");
InBookKey(k);//输入要查找书的关键字
printf("\n");
rs=SearchBTree(root,k);
if(rs.tag==1){
ShowBookMess(rs.pt->key[rs.i]);//显示一本书的具体信息
}
else{
printf("\t你要查找的书号%d不存在!
\n\n",k.key);
}
printf("\n\t------------------查找结束----------------\n");
break;
case'6':
system("cls");
printf("\t------------------借阅-----------------\n");
borrow(root);
break;
case'7':
system("cls");
printf("\t-----------------还书-----------------\n\n");
payback(root);
break;
case'8':
printf("\n\t你想退出吗?
(y/n)");
t=getch();
if(t=='y'||t=='Y')exit(0);
break;
default:
break;
}
printf("\n\t按任意键返回主菜单....");
getch();
system("cls");
}
}
(5)程序组织
第四部分:
功能模块函数设计和调试
/*************菜单界面***********/
voidprint()
{
printf("\n╔══════════════╗");
printf("\n║欢迎进入图书管理系统║");
printf("\n╚══════════════╝");
}
charmenu()//显示菜单函数,返回接收的字符
{printf("\n");
printf("\n1.新书入库\n2.删除旧书\n3.显示书库\n4.凹入显示\n5.查找图书\n6.读者借书\n7.读者还书\n8.退出系统\n");
printf("\n");
printf("\n");
printf("\t\t\t>>>>>>>>>请选择<<<<<<<<<<\n");
printf("\n");printf("\n");
printf("\t\t");
fflush(stdin);//清除缓存
returngetchar();//接受菜单命令
}
//*************新书入库***********//
/*************输入添加书的内容***********/
voidInBookMess(Books&book){
chars[5];
printf("\t请输入书号:
");
scanf("%s",s);
book.key=atoi(s);
printf("\t请输入书名:
");
scanf("%s",&book.bname);
printf("\t请输入作者:
");
scanf("%s",&book.writter);
printf("\t请输入总量:
");
scanf("%s",s);
book.total=atoi(s);//将字符串转化为整型树
book.left=book.total;
for(inti=0;ibook.reader[i].number[0]='\0';
}
/*************插入新书,在B树中插入新结点***********/
intInsertBTree(BTree&T,BooksK){
//在m阶B树T上结点*q的key[i]与key[i+1]之间插入关键字K。
BTreeap;
Resultrs;
BTreeq;
inti;
charaddnum;
intfinished,needNewRoot,s;
Booksx;
if(!
T){
NewRoot(T,NULL,K,NULL);
}
else{
rs=SearchBTree(T,K);//查找元素k在树中的位置
q=rs.pt;
i=rs.i;
if(rs.tag==1){
if(strcmp(q->key[i].bname,K.bname)!
=0){
printf("\n\t录入失败,原因:
\n");
printf(".\t书号冲突,请重新为该书编号!
\n\n");
printf("\t已经存在书号为%d的书为:
\n",q->key[i].key);
ShowBookMess(q->key[i]);
return0;
}
else
{
printf("\n\t该书已经存在!
\n\n");
printf("\t是否增加其总量(y/n):
");
getchar();
scanf("%c",&addnum);
if(addnum=='Y'||addnum=='y'){
q->key[i].total+=K.total;
q->key[i].left+=K.total;
printf("\n\t增加总量后该书的信息如下\n");
}
else{
printf("\n\t该书的信息如下:
\n");
}
ShowBookMess(q->key[i]);
return0;
}
}
x=K;
ap=NULL;
finished=needNewRoot=0;
while(!
needNewRoot&&!
finished){
Insert(q,i,x,ap);//插入结点
if(q->keynumfinished=1;//插入完成
else{//分裂结点*q
s=(m+1)/2;
split(q,s,ap);
x=q->key[s];
if(q->parent){//在双亲结点*q中查找x的插入位置
q=q->parent;
i=Search(q,x);
}
else
needNewRoot=1;
}
}
if(needNewRoot)
NewRoot(T,q,x,ap);//生成新根结点*T,q和ap为子树指针
}
return1;
}
/*************凹入表示法输入***********/
voidmball(BTreebth,intnum)//以brh为根节点的凹入输出
{
BTreep;
inti,j;
p=bth;//当前指向要输出的结点的指针
if(p)//结点非空
{
for(j=0;jprintf("");
for(i=1;i<=p->keynum;i++)
{
//k=t;
printf("%d",p->key[i].key);//顺序输出该结点的关键字
//t=k;
}
printf("\n");
for(i=0;i<=p->keynum;i++)
mball(p->ptr[i],num+1);
//顺序递归访问该结点的各个子结点
}
}
//*************删除旧书***********//
/*************删除一个关键字***********/
voidDeleteBTree(BTree&T)//在m阶B-树T上删除关键词
{
Booksx;//要删除
Resultrs;
BTreeq,p;
inti,j,s=(m+1)/2;
charisdel;//输入的是y还是n
printf("\n");
printf("\n\t请输入你想要删除的书的关键字(即书号):
");
scanf("%d",&x.key);//x为要删的关键字
rs=SearchBTree(T,x);//找到x在B-树中的位置
if(rs.tag==0)
{
printf("\n\t这本书不存在!
\n");
return;
}
printf("\n\t你确定删除这本书吗?
(y/n)");
getchar();
scanf("%c",&isdel);
if(isdel=='n'||isdel=='N')
return;
elseif(isdel=='y'||isdel=='Y')
{
while(rs.pt->ptr[rs.i])//转化为叶子节点删除
{
rs.pt->key[rs.i]=rs.pt->ptr[rs.i]->key[1];
rs.pt=rs.pt->ptr[rs.i];
rs.i=1;
}
p=rs.pt;//指向要删除关键字的结点
i=rs.i;//删除的关键词p->key[i]位置
for(j=i;jkeynum;j++)//删除p->key[i]和p->ptr[i]
{
p->key[j]=p->key[j+1];
p->ptr[j]=p->ptr[j+1];
}
p->keynum--;
while((p->keynum=T))
{
q=p->parent;
i=0;
while(p!
=q->ptr[i])//找出p结点为其双亲结点q的第i个孩子;
i++;
if(i==0)//结点p为最左边的孩子
{
if(q->ptr[1]->keynum>s-1)//右兄弟是否有多余的关键字
MoveLeft(q,1);
else
Merge(q,1);
}
elseif(i==q->keynum)//结点p为最右边的孩子
{
if(q->ptr[i-1]->keynum>s-1)
MoveRight(q,i);
else
Merge(q,i);
}
elseif(q->ptr[i-1]->keynum>s-1)//结点p为中间孩子,先检查左兄弟
MoveRight(q,i);
elseif(q->ptr[i+1]->keynum>s-1)//再检查右兄弟
MoveLeft(q,i+1);
elseMerge(q,i);
p=q;
}
if(T->keynum==0)//根结点被合并,整个B-树降低一层
{
q=T;
T=T->ptr[0];
free(q);
}
}
}
voidMoveLeft(BTree&q,inti)//将一个关键词经结点q移到左兄弟中,q为要删关键字结点的双亲结点
{
intj;
BTreer=q->ptr[i-1];//指向左结点
r->keynum++;
r->key[r->keynum]=q->key[i];//从双亲结点q移动关键词到左结点中
r->ptr[r->keynum]=q->ptr[i]->ptr[0];
r=q->ptr[i];//指向右子树
q->key[i]=r->key[1];//将右结点树中第一个关键词移到双亲结点q中
r->ptr[0]=r->ptr[1];
r->keynum--;
for(j