基于C语言实现B树存储的图书管理系统
一、需求分析
1.1 问题描述
图书管理基本业务活动包括:对一本书的采编入库、清除库存、借阅和归还等等。试设计一个图书管理系统,将上述业务活动借助于计算机系统完成。
1.2 基本要求
每种书的登记内容至少包括书号、书名、著者、现存量和总库存量等五项。
作为演示系统,不必使用文件,全部数据可以都在内存存放。但是由于上述四项基本业务活动都是通过书号(即关键字)进行的,所以要用B树(2-3树)对书号建立索引,以获得高效率。
系统应实现的操作及其功能定义如下:
①采编入库:新购入一种书,经分类和确定书号之后登记到图书账目中去。如果这种书在帐中已有,则只将总库存量增加。
②清除库存:某种书已无保留价值,将它从图书账目中注销。
③借阅:如果一种书的现存量大于零,则借出一本,登记借阅者的图书证号和归还期限。
④归还:注销对借阅者的登记,改变该书的现存量。
⑤显示:以凹入表的形式显示B树。这个操作是为了调试和维护的目的而设置的。下列B树的打印格式如下所示:

1.3 已完成情况
|------------------------|-----------------|---------------------------------|-------------------|
| 基本功能 | | 选做功能 | |
| 图书入库 | 已完成 | 操作日志 | 已完成 |
| 删除图书 | 已完成 | 查询作者著作 | 已完成 |
| 借书 | 已完成 | 查询书籍状态 | 已完成 |
| 还书 | 已完成 | 预约借书 | 已完成 |
| 拓展功能 | 拓展功能 | 拓展功能 | 拓展功能 |
| 查询读者状态 | 查询读者状态 | 查询读者的借阅、预约列表(已完成) | 查询读者的借阅、预约列表(已完成) |
| 总结 | 总结 | 总结 | 总结 |
| 1、图书管理系统的四个基本功能已经全部完成。 | 2、选择内容四个功能全部完成。 | 3、增加了一个拓展功能,可以更具读者借书证号查询他的借阅状态。 | |
1.4 程序亮点
亮点一:系统输入排错功能完善,处理用户的乱输入乱操作,增加了系统的稳健性。

亮点二:系统功能有序,使用功能界面完善,用户体验效果好

二、概要设计
2.1 数据类型的定义

2.2 功能模块关系

三、详细设计
3.1 数据类型定义
typedef struct{ //被借阅的书籍
int tag; //状态: 0->预约,1->借阅
int readerId; //读者id
int borrowTime; //出借时间
int backTime; //归还时间
char readerName[30]; //读者名字
char bookName[30]; //书籍名字
}LendBook, *LendBookP;
typedef struct linkNode {
int type; //类型:0->借阅记录、1->操作记录、3->作家的书
LendBook *lenBook; //借阅记录
char *log; //操作记录
char *book; //作家的书
struct linkNode *next;
}LinkNode, *LinkType;
typedef struct{ //书籍
int id; //书籍id
char name[30]; //书名
int authorId; //作者id
char authorName[30]; //作者
int totalNum; //书籍数量
int stockNum; //书籍库存
LinkNode *borrowList; //借阅列表
LinkNode *appointList; //预约列表
}Book;
typedef struct{ //作者
int id; //作者id
char name[30]; //作者名字
LinkNode *bookList; //出版书籍
}Author;
typedef struct{ //读者
int id; //读者id
char name[30]; //读者名字
LinkNode *borrowList; //借阅列表
LinkNode *appointList; //预约列表
}Reader;
typedef struct rcdNode{
int type; //结构体数据类型:
//0->书籍、1->作者、2->读者
Book *book; //书籍
Author *author; //作者
Reader *reader; //读者
}RcdNode, *RcdType;
typedef struct BTNode{ //B树和B树结点类型
int keynum; //结点关键字个数
KeyType key[MAXM]; //关键字数组,key[0]不使用
BTNode *parent; //双亲结点指针
BTNode *ptr[MAXM]; //孩子结点指针数组
RcdNode *rcd[MAXM];
}BTNode,*BTree;
typedef struct{ //B树查找结果类型
BTNode *pt; //指向找到的结点
int i; //在结点中的关键字位置;
int tag; //查找成功与否标志
}Result;
typedef struct LNode{ //链表和链表结点类型
BTree data; //数据域
struct LNode *next; //指针域
}LNode, *LinkList;
3.2 函数功能具体设计
- 图书入库

- 删除图书

- 预约借书

- 借书

- 还书

- 查询图书

- 查询作者

- 查询读者

- 查看全部(打印B树)

- 操作日志

四、调试分析
4.1 问题分析与解决
难题一:图书、作者、读者数据存储定义。
一开始构思的时候,并没有打算将作者和读者也用B树存储起来,初步设想是用两个链表。但是后来想到查询作者和查询读者的查询难度和查询书籍应该一个等级,所以用B树存储的话能够提高查询速度和存储效率,所以选择了给图书、作者、读者分别用一个B树存储起来。
难题二:数据结构体之间的关系设计。
在图书、作者、读者关系里面,他们互有指向又相互独立,所以三者的结构体以及对应信息的指针指向就需要好好梳理。举个例子,图书里面要有借阅信息,读者里面也要有借阅信息,而借阅信息里面有图书信息和读者信息。
结构体的定义指向不能形成闭环,所以为了实现我将图书信息里面的图书名称和读者信息里面的作者名称抽取出来,放到了借阅信息里面。而关于借阅信息链表的增删改查,关键信息也就变成了作者名称和图书名称。
难题三:日期的定义。
无论是借书、预约、还书,都和日期有关,直接让用户输入时间的话可能引发诡异的BUG,所以,我将这个系统的日期做了简化,初始默认是第一天,每一个操作增加一天,用户借书、预约的时候都是只输入一个借书天数num,程序会将这个天数处理,所以,借书的时候以今天第x天为借书日期,还书日期就是第x+num天,而预约成功的话,就以这本书被上一个借走的人还书的那一天y为借书日期,还书日期就是y+num。当然,这个方法有些取巧,但是能简化预约功能的实现和合理化整体系统的功能。
4.2 经验体会
最大的体会就是,如果要设计一个整体性功能完善的系统的话,一开始一定要构思好整体的逻辑,包括各种功能的具体定义、实现的合理性、交互的实用性以及功能和功能之间整体性。功能和功能之间,关联性是很强的,一旦一个功能发生改变或者增删某一个功能的时候,其他的许多逻辑也要跟着改,这是很没必要也很浪费时间的。举个例子,我一开始并没有将读者查询、作者查询放入我的规划功能里面,所以结构体的定义都是基于图书B树来的,后来想要尝试选做内容的时候,整体上逻辑大改,结构体修改和新定义了一大堆。
再来就是,灵活debug吧,c语言的封装性比较强,很多bug都隐藏在这个指针和那个指针之间,如果不用特殊方法去检测的话是很难找出来的。所以要灵活利用断点、打印printf这些来实现程序的实时监控。
最后呢就是,坚持、耐心、细心。这三个在这次课设都充分地帮助到了我,让我在一次又一次的逻辑闭环和死debug的苦海中挣脱出来。
五、用户使用说明
5.1 功能菜单

5.2 使用说明
基本用法:用户通过a~k等11个字母输入选择具体功能。
特殊说明:
- 每一次使用完一个功能之后会重新清空命令行重新渲染菜单
- 每一次使用完一个功能之后日期会增加一天
- 日期输入采取简化输入,用户输入x,代表第x天
- 当前日期显示在菜单右下角
- 一个人预约一本书的话,会在上一个读者还书的时候帮他成功预约
测试数据:
作者:
- 序号1------"曹雪芹" 序号2------"吴承恩" 序号3------"施耐庵"
- 序号4------"罗贯中" 序号5------"唐家三少" 序号6------"天蚕土豆"
- 序号7------"江南"
读者:
- 读书证号111------"小红" 读书证号222------"小明"
- 读书证号333------"小华"
书籍:(书号和作家序号相对应)
- 书号1------《红楼梦》 书号2------《西游记》 书号3------《水浒传》
- 书号4------《三国演义》 书号5------《斗罗大陆》 书号6------《斗破苍穹》
- 书号7------《龙族IV》
六、测试结果
6.1 图书入库
示例:加入书籍《数据结构》(书号:12)------李教授(作者序号:12)
亮点:输入非数字排错处理

6.2 删除图书
示例:删除书籍《三国演义》(书号:4)
亮点:输入不存在书号排错处理


6.3 预约借书
示例:小明(读书证号222)预约书籍《数据结构》(书号:12)
亮点:书号、借书证号、借书天数的排错处理

6.4 借书
示例:小红(读书证号111)借阅书籍《数据结构》(书号:12)
亮点:书号、借书证号、借书天数的排错处理

6.5 还书
示例:小红(读书证号111)还书《数据结构》(书号:12)
亮点:
- 没有借阅书籍读者、没有借阅记录的书籍的排错处理
- 还书之后,该书如有预约,成功预约



6.6 查询图书

6.7 查询作者

6.8 查询读者

6.9 查看全部(打印B树)

6.10 操作日志
