0
点赞
收藏
分享

微信扫一扫

C语言课设--文献管理系统

止止_8fc8 2022-01-16 阅读 32
c语言

C语言课设--文献管理系统

一、 需求分析

题目:文献管理系统
【问题描述】
设计一个文献管理系统,使用B树结构实现对文献的入库、清除库存、借阅和归还等操作。
【基本要求】
(1) 文献登记的内容至少包括文献号、文献名、著者、现存量和总库存量等五项。
(2) 文献信息可使用文件存储,也可只在内存存储。文献号作为关键字,使用3阶B树对文献号建立索引。
(3) 系统实现的操作及其功能定义如下:
①入库:新购入的文献,确认文献号之后登记到系统。如果这种文献在系统中已有,则只将总库存量增加。
②清除:某种文献已无保留价值,将它从系统中注销。
③借阅:如果一种文献的现存量大于零,则借出一本,登记借阅者的证件和归还期限。
④归还:注销对借阅者的登记,改变该文献的现存量。
⑤显示:以凹入表的形式显示B树。
【扩展要求】
(1) 将程序一次运行的操作记入日志文件中。
(2) 增加列出某著者全部文献名操作
(3) 增加列出某种文献状态的操作。状态信息除了包括这种文献记录的全部信息外,还包括最早到期的借阅者证件。
(4) 增加预约借阅文献功能
(5) 使用4阶以上B树重新实现文献管理系统

二、概要设计

  1. 数据对象
    B树是一种平衡的多路查找树。
  2. B树的数据关系
    一颗m阶B树,或为空树,或为满足下列特性的m叉树。
    (1)树中每个结点最多含有m棵子树;
    (2)若根结点不是叶子结点,则至少有两颗子树;
    (3)除根之外的所有非终端结点至少有[m/2];
    (4)每个非终端结点中包含信息:(n,A0,K1,A1,K2,A2,…,Kn,An)。其中
    ①Ki(1≤i≤n)为关键字,且关键字按升序排序。
    ②指针Ai(0≤i≤n)指向子树的根结点。
    ③关键字的个数n必须满足:[m/2]-1≤n≤m-1
    (5)所有的叶子结点都出现在同一层次上,并且不带信息(可以看作是外部节点或查找失败的结点,实际上这些结点不存在,指向这些结点的指针为空)
  3. B树基本操作
  1. void InitBTNode(BTree &p);
    初始条件:结点p存在。
    操作结果:初始化结点。
  2. int InsertBTree(BTree &T, int k, Record rcd);
    初始条件:结点T存在。
    操作结果:在B树中插入关键字为k的记录rcd
  3. void split(BTree &q, BTree &ap); //分裂饱和结点
    初始条件:结点q和结点ap已存在。
    操作结果:将结点q分裂成两个结点,前一半保留,后一半移入结点ap。
  4. void newRoot(BTree &T, BTree p, BTree ap, int k, Record rcd);
    初始条件:结点T,p,ap已存在。
    操作结果:生成新的根结点T原p和ap为子树指针
  5. void Insert(BTree &q, int k, int index, BTree ap, Record rcd); //插入关键字及指针ap
    初始条件:结点q和结点ap已存在,0<indexkeynum
    操作结果:将关键字k和结点ap分别插入到q->key[index+1]和q->ptr[index+1]中
  6. int DeleteBTree(BTree &T, int key); //删除索引为key的记录
    初始条件:B树T已存在
    操作结果:在B树T中删除关键字key
  7. void Successor(BTree &node, int &index);
    初始条件:B树node已存在
    操作结果:将直接前驱的索引和值覆盖掉当前结点
  8. int Remove(BTree& node, int i);
    初始条件:结点node已存在,0<ikeynum
    操作结果:node结点删除key[i]和它的孩子指针ptr[i]
  9. int InsertRecord(BTree& node, int key,int i, Record rcd);
    初始条件:结点node已存在,0<ikeynum
    操作结果:向父结点插入关键字
  10. void Restore(BTree& node, int index);
    初始条件:结点node已存在,0<indexkeynum
    操作结果:调整node,使得B树正常
  11. void CombineBTNode(BTree& l_node, BTree& r_node);
    初始条件:结点l_node,r_node已存在
    操作结果:将右节点数据调整至左节点,释放右节点
  12. void DeleteRoot(BTree& root);
    初始条件:结点root已存在
    操作结果:将合并后结点中所有记录插入到父节点中
  13. void Traverse(BTree t, int k);
    初始条件:B树t已存在
    操作结果:遍历B树
  14. void PrintBTree(BTree t);
    初始条件:B树t已存在
    操作结果:遍历打印B树
  15. void SearchBTree(BTree T, int k, result &r);
    初始条件:结点T已存在
    操作结果:在结点T中查找关键字k的插入位置i,1) 用r返回(pt,i,tag)
  16. int Search(BTree p, int k);
    初始条件:结点p已存在
    操作结果:在p->key[1…p->keynum]中查找p->key[i-1]<k<=p->key[i]
  1. 文献管理数据类型定义
    (文献,借阅者,预约者)存储结构定义
    typedef int KeyType; //书号BookId类型

typedef struct Borrower{
int borrowerId; //借阅者图书证号
char name[20]; //借阅者姓名
time_t time; //归还时间
struct Borrower *next; //借阅者信息用链表
}BorrowerType; //借阅者类型

typedef struct {
char bookName[30]; //书名
char writerName[20]; //作者
char bookPress[30]; //出版社
int booknumNow; //现存量
int booknumAll; //总库存量
BorrowerType * borrower;
BorrowerType * booker;
}BookType; //文献类型
5. 文献基本操作
//图书管理的操作接口
void InsertBook(BTree &T, int k, BookType* book);
//采编入库
void DeleteBook(BTree &t, KeyType key);
//清除库存
void BorrowBook(result r,int number,char *name,int *flag);
//借阅图书
int HasBorrow(result r,int number,char *name);
//判断是否借过 0表示借过
int ReturnBook(result r, int number, char *name);
//归还图书
void ShowBookAll(BTree t, KeyType key);
//查看某种图书的信息(包括借阅者)
int SearchByWriter(BTree t,char *name, int *flag);
//根据作者搜索书名
int SearchByBorrower(BTree t,int number,char *name, int *flag);
//根据借阅者搜索书名
void ShowBook(BTree t, KeyType key);
//输出某本书的信息
void addBook(BTree t, KeyType key, int num);
//添加某本书的数量
int emtyBook(BTree q, int i);
//检查某本书的现存量是否大于0
void TraverseBook(BTree t);
//遍历输出所有文献信息
void Booking(result r,int number,char *name,int *flag);
//预约文献
int CancelBooking(result r,BorrowerType *booker);
//预约文献减去 1:成功
//界面展示
void Welcome(); //欢迎界面
void Choose(); //身份选择界面
int Login(); //管理员登录验证界面
void Menu_manager(); //管理员菜单
void Menu_borrower(); //借阅者菜单
//data
void log_reocrd(int error_level, const char format, …); //日志记录
void Init(BTree &t); //读取图书文件
void Save(BTree &T);
void save_btree(BTree &T, FILE
fp);
6.程序设计图
主菜单(选择身份)

管理员菜单

借阅者菜单

各程序模块的调用关系

三、详细设计
1.B树结构的实现
typedef struct BTNode{
int keynum; //结点当前的关键字个数
int key[m+1]; //索引数组,key[0]不用
struct BTNode* parent; //双亲结点指针
struct BTNode* ptr[m+1]; //孩子结点指针数组
BookType* books[m+1]; //书本数组,books[0]不用
}BTNode, *BTree;

typedef struct{
int index; //1<=index<=m,在结点中的关键字位序
int tag; //1:查找成功,0:查找失败
BTNode* node; //指向找到的结点
}result;

//insert
void InitBTree(BTree &t); //初始化树
void InitBTNode(BTree &p); //初始化结点
int InsertBTree(BTree &T, int k, BookType* book); //插入结点
void split(BTree &q, BTree &ap); //分裂饱和结点
void newRoot(BTree &T, BTree p, BTree ap, int k, BookType* book); //创建新根结点
void Insert(BTree &q, int k, int index, BTree ap, BookType* book); //插入关键字及指针ap

//delete
int DeleteBTree(BTree &T, int key); //删除索引为key的记录
void Successor(BTree &node, int &index); //若不是终端结点,将直接前驱的索引和值覆盖掉当前结点
int Remove(BTree& node, int i); //从结点p中删除key[i]
int InsertBookType(BTree& node, int key,int i, BookType* book); //向父结点插入关键字
void Restore(BTree& node, int index); //调整树
void CombineBTNode(BTree& l_node, BTree& r_node); //合并结点
void DeleteRoot(BTree& root); //将合并后结点中所有记录插入到父节点中

//print
void Traverse(BTree t, int k); //遍历B树
void PrintBTree(BTree t); //打印B树

//search
void SearchBTree(BTree T, int k, result &r); //在m阶B树t上查找索引k,用r返回(pt,i,tag)
int Search(BTree p, int k); //在p->key[1…p->keynum]中查找p->key[i-1]<k<=p->key[i]

delete.cpp
#include “includes.h”

int DeleteBTree(BTree &T, int key){
//删除索引为key的记录
result r;
SearchBTree(T, key, r);
if (r.tag == 0) return 0;
//若不是终端结点,将直接前驱的索引和值覆盖掉当前结点
if (r.node->ptr[0] != NULL) Successor(r.node, r.index);
//更新key的值为前驱结点
key = r.node->key[r.index];
//从结点p中删除key[i]
Remove(r.node, r.index);
//找到
int index = Search(r.node->parent, key) - 1;
//调整树
if (r.node->parent != NULL && r.node->keynum < MIN_NUM)
Restore(r.node, index);
return 1;
}

//若不是终端结点,将直接前驱的索引和值覆盖掉当前结点
void Successor(BTree &node, int &index){
if(node == NULL) return;
//寻找直接前驱
if(node->ptr[index - 1] == NULL) return;
BTree p = node->ptr[index - 1];
while(p->ptr[p->keynum] != NULL)
p = p->ptr[p->keynum];
//将直接前驱的索引和值覆盖掉当前结点
node->key[index] = p->key[p->keynum];
node->books[index] = p->books[p->keynum];
//令node指向待删除的直接前驱结点
node = p;
index = p->keynum;
}

//从结点p中删除key[i]
int Remove(BTree& node, int i){
if (node == NULL) return 0;
//将删除结点后结点前移
for (; i < node->keynum; i++) {
node->key[i] = node->key[i+1];
node->books[i] = node->books[i+1];
}
node->keynum–;
return 1;
}

//向父结点插入关键字
int InsertBookType(BTree& node, int key,int i, BookType* book) {
if (node == NULL) return 0;
for (int j = node->keynum; j >= i; j–) {
node->key[j + 1] = node->key[j];
node->books[j + 1] = node->books[j];
}
node->key[i] = key;
node->books[i] = book;
node->keynum++;
return 1;
}

//调整树
void Restore(BTree& node, int index) {
BTree parent,l_brother, r_brother;
parent = node->parent;
//左兄弟够借
if (index > 0 && (l_brother = parent->ptr[index - 1])->keynum > MIN_NUM) {
//该节点插入直接前驱
Insert(node, parent->key[index], 1, node->ptr[0], parent->books[index]);
//改变孩子指针
node->ptr[0] = l_brother->ptr[l_brother->keynum];
if (l_brother->ptr[l_brother->keynum] != NULL) l_brother->ptr[l_brother->keynum]->parent = node;
//移除父节点中其直接前驱
Remove(parent, index);
//将直接前驱的直接前驱插入到父节点
InsertBookType(parent, l_brother->key[l_brother->keynum], index, l_brother->books[l_brother->keynum]);
//将直接前驱的直接前驱删除
Remove(l_brother, l_brother->keynum);
}
//左兄弟不够,右兄弟够借
else if (index < parent->keynum && (r_brother = parent->ptr[index + 1])->keynum > MIN_NUM) {
Insert(node, parent->key[index+1], node->keynum + 1, r_brother->ptr[0], parent->books[index + 1]);
Remove(parent, index + 1);
InsertBookType(parent, r_brother->key[1], index + 1, r_brother->books[1]);
Remove(r_brother, 1);
for (int i=0; i <= r_brother->keynum; i++) r_brother->ptr[i] = r_brother->ptr[i + 1];
}
//兄弟不够借,合并左子树
else if (index > 0) {
l_brother = parent->ptr[index - 1];
Insert(node, parent->key[index], 1, node->ptr[0], parent->books[index]);
Remove(parent, index);
CombineBTNode(l_brother, node);
node = l_brother;
for (int i = index; i <= parent->keynum; i++) parent->ptr[i] = parent->ptr[i + 1];
//调整父节点至平衡
if (parent->keynum < MIN_NUM) {
if (parent->parent == NULL) DeleteRoot(parent);
else Restore(parent, Search(parent->parent, node->key[1]) - 1);
}
}
//兄弟不够借,合并右子树
else {
r_brother = parent->ptr[index + 1];
Insert(node, parent->key[index+1],node->keynum + 1, r_brother->ptr[0], parent->books[index + 1]);
Remove(parent, index + 1);
CombineBTNode(node, r_brother);
for (int i = index + 1; i <= parent->keynum; i++)
parent->ptr[i] = parent->ptr[i + 1];
//调整父节点至平衡
if (parent->keynum < MIN_NUM) {
if (parent->parent == NULL) DeleteRoot(parent);
else Restore(parent, Search(parent->parent, node->key[node->keynum + 1]) - 1);
}
}
}

//合并结点
void CombineBTNode(BTree& l_node, BTree& r_node) {
//左结点为空返回
if (l_node == NULL) return;
//将右结点所有记录合并到左结点
for (int i = 1; i <= r_node->keynum; i++) {
Insert(l_node, r_node->key[i], l_node->keynum + 1, r_node->ptr[i], r_node->books[i]);
}
//释放右节点
free(r_node);
return;
}

//将合并后结点中所有记录插入到父节点中
void DeleteRoot(BTree& root) {
BTree node = root->ptr[0];
//父节点指向node的孩子
root->ptr[0] = node->ptr[0];
//非终端结点,孩子结点指向父节点
if (node->ptr[0] != NULL) node->ptr[0]->parent = root;
//将所有记录插入到父节点
for (int i = 1; i <= node->keynum; i++) Insert(root, node->key[i], i, node->ptr[i], node->books[i]);
//释放该节点
free(node);
return;
}

Insert.cpp
#include “includes.h”

//创建
void InitBTree(BTree &t) {
BookType* books[18];
KeyType key[] = { 35,14,17,71,3,54,21,62,13,16,12,45,27,42,10,90,88,7 };
int num[] = { 1,6,41,87,5,12,40,51,64,73,5,40,47,50,59,98,87,85 };
char name[18][30] = { “数据结构”,“简明大学物理学”,“大学物理学(上册)”,“大学物理实验”,“电路(第5版)”,“电工与电子技术实验教程”,“C语言程序设计”,
“复变函数(第二版)”,“半导体物理”,“概率论与数理统计”,“专业实验基础”,“离散数学及其应用”,“高等数学(上册)”,“高等数学(下册)”,
“计算机科学概论”,“线性代数”,“电工学(上册)”,“电工学(下册)” };
char writer[18][40] = { “吴伟民”,“范仰才”,“范仰才”,“朱道云”,“邱关源”,“彭端”,“王绵森”,“刘恩科”,“旭里”,“微电子系”,
“朱平”,“傅彦”,“同济大学数学系”,“同济大学数学系”,“张爱红”,“同济大学数学系”,“苏林”,“刘成悦” };
char press[18][40] = { “高等教育出版社”,“高等教育出版社”,“北京大学出版社”,“北京大学出版社”,“高等教育出版社”,
“吉林大学出版社”,“高等教育出版社”,“电子工业出版社”,“化学工业出版社”,“广东工业大学出版社”,“广西师范大学出版社”,
“高等教育出版社”,“高等教育出版社”,“高等教育出版社”,“人民邮电出版社”,“高等教育出版社”,“复旦大学出版社”,“复旦大学出版社” };
int j,n=18;
for (j = 0;j < n;j++) { //逐一插入元素
books[j] = (BookType *)malloc(sizeof(BookType));
strcpy(books[j]->bookName,name[j]);
strcpy(books[j]->writerName, writer[j]);
strcpy(books[j]->bookPress, press[j]);
books[j]->booknumAll = num[j];
books[j]->booknumNow = num[j];
books[j]->borrower = NULL;
books[j]->booker = NULL;
InsertBTree(t,key[j],books[j]);
}
}

void InitBTNode(BTree &p){
p = (BTree)malloc(sizeof(BTNode));
//对p的子节点初始化
for(int i = 0;i<=m+1;i++){
p->key[i] = -1;
p->ptr[i] = NULL;
// p->books[i].bookName = NULL;
}
p->keynum = 0;
p->parent = NULL;
return;
}

int InsertBTree(BTree &T, int k, BookType* book){
result result;
//查找是否已经存在
SearchBTree(T, k, result);
if(result.tag) return 0; //已存在则不执行插入
Insert(result.node, k, result.index, NULL, book);
BTree ap;
while (result.node->keynum >= MAX_NUM ){
split(result.node, ap);
k=result.node->key[SPLIT_INDEX];
if (result.node->parent == NULL){
//最顶层
newRoot(T, result.node, ap, k, result.node->books[SPLIT_INDEX]);
k = -1;
}
else {
int index = Search(result.node->parent, k); //在双亲结点中查找k的插入位置
Insert(result.node->parent, k, index, ap, result.node->books[SPLIT_INDEX]);
}
result.node = result.node->parent; //上移一层
if(result.node==NULL) break;
}
return 1;
}

void split(BTree &q, BTree &ap){
//将q结点分裂成两个结点,前一半保留在原节点,另一半移入ap所指向的新节点
int i, j, n = q->keynum;
ap = (BTNode*)malloc(sizeof(BTNode)); //生成新结点
InitBTNode(ap);
ap->ptr[0] = q->ptr[SPLIT_INDEX];
for(i = SPLIT_INDEX + 1, j = 1; i<=n;i++,j++){ //后一半移入ap结点
ap->key[j] = q->key[i];
ap->ptr[j] = q->ptr[i];
ap->books[j] = q->books[i];
q->key[i] = -1;
q->ptr[i] = NULL;
}
ap->keynum = n-SPLIT_INDEX;
ap->parent = q->parent;
for(i=0;i<=n-SPLIT_INDEX;i++) //修改新结点的子节点的parent域
if(ap->ptr[i]!=NULL) ap->ptr[i]->parent = ap;
q->keynum = SPLIT_INDEX - 1; //q的前一半保留,修改keynum
return;
}

void newRoot(BTree &t, BTree p, BTree ap, int k, BookType* book){ //生成新的根节点 p是左子树 ap是右子树
t = (BTNode*)malloc(sizeof(BTNode));
t->keynum = 1;
t->ptr[0] = p;
t->ptr[1] = ap;
t->key[1] = k;
t->books[1] = book;
if(p!=NULL) p->parent = t;
if(ap!=NULL) ap->parent = t;
t->parent = NULL; //新根的双亲是空指针
}

void Insert(BTree &q, int k, int index, BTree ap, BookType* book){
//关键字k和新结点指针ap分别插入到q->key[i]和q->ptr[i]
int i;
//将待插入结点后的所有结点后移
for(i = q->keynum; i>=index; i–){
q->key[i+1] = q->key[i];
q->ptr[i+1] = q->ptr[i];
q->books[i+1] = q->books[i];
}
q->key[index] = k;
q->ptr[index] = ap;
q->books[index] = book;
if(ap!=NULL) ap->parent = q;
q->keynum++;
return;
}
Print.cpp
#include “includes.h”

//遍历B树
void Traverse(BTree t, int k) {
if (t != NULL) {
int i;
for (i = 1;i <= t->keynum;i++) {
//非终端结点
if (t->ptr[i - 1] != NULL) {
if (i == 1) {
for (int j = 1;j <= (k * 2);j++) printf(" “);
for (int j = 1;j <= t->keynum;j++) {
if (j == t->keynum) printf(”%d\n", t->key[j]);
else printf("%d,", t->key[j]);
}
k++;
}
}
//终端结点
else {
if (i == 1 && i == t->keynum) {
for (int j = 1;j <= (k * 2);j++) printf(" “);
printf(”%d\n", t->key[i]);
}
if (i == 1 && i < t->keynum) {
for (int j = 1;j <= (k * 2);j++) printf(" “);
printf(”%d,", t->key[i]);
}
if (i != 1 && i < t->keynum) {
printf("%d,", t->key[i]);
}
if (i != 1 && i == t->keynum) {
printf("%d\n", t->key[i]);
}
}
if (i == 1)
Traverse(t->ptr[i - 1], k);
Traverse(t->ptr[i], k);
}
}
}

//凹入表输出
void PrintBTree(BTree t) {
printf(“当前B树的状态如下:\n”);
if (t == NULL)
printf(“此B树为空树\n”);
else
Traverse(t, 0);
}
Search.cpp
#include “includes.h”

void SearchBTree(BTree t, int k, result &r){
int i = 0, found = 0;
//在m阶B树t上查找索引k,用r返回(pt,i,tag)
//如果查找成功,则标记tag=1,指针pt所指结点中第i个索引等于k
//否则tag=0,若要插入索引为k的记录,应位于pt结点中第i-1个和第i个索引之间
BTree p = t, q = NULL;
while(p!=NULL&&0==found){
i = Search(p, k); //在p->key[1…p->keynum]中查找p->key[i-1]<k<=p->key[i]
if(i<=p->keynum && p->key[i]==k) found = 1; //找到待查索引
else{
q = p;
p = p->ptr[i-1];
}//指针下移
}
if(1 == found){//查找成功,返回k的位置p及i
r.node = p; r.index = i; r.tag = 1;
}else{ //查找不成功,返回k的插入位置q及i
r.node = q; r.index = i; r.tag = 0;
}
return;
}
//在p->key[1…p->keynum]中查找p->key[i-1]<k<=p->key[i]
int Search(BTree p, int k){ //在p->key[1…p->keynum]找k
int i=1;
while(i <= p->keynum&&k>p->key[i]) i++;
return i;
}
2.文献管理系统实现
Inlcudes.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include<windows.h>
using namespace std;

#define m 4 //B树的阶
#define MAX_NUM m //关键字上限
#define MIN_NUM (m-1)/2 //除头结点外关键字下限
#define SPLIT_INDEX (m+1)/2 //分裂处下标
extern time_t now;//系统时间

enum {Error,Waring,Info,Debug};

//宏定义日志
#define LogRecord(_error_level,_fmt,_X…)
do {
time_t _current_time=time(NULL);
char _file_name[256]="\0";
strftime(_file_name,sizeof(_file_name),"%Y-%m-%d_LOG_RECORD.log",localtime(&_current_time));
FILE *_fp=NULL;
_fp=fopen(_file_name,“a+”);
if(_fp!=NULL)
{
char _time_str[32];
strftime(_time_str,sizeof(_time_str),"%Y-%m-%d %H:%M:%S",localtime(&_current_time));
if(_error_levelError)
{
fprintf(_fp,"[%s]-[%s]-[%s]-[%d] :> “_fmt”\n",_time_str,“Error”,FILE,LINE,##_X);
}
else if(_error_level
Waring)
{
fprintf(_fp,"[%s]-[%s]-[%s]-[%d] :> “_fmt”\n",_time_str,“Waring”,FILE,LINE,##_X);
}
else if(_error_levelInfo)
{
fprintf(_fp,"[%s]-[%s]-[%s]-[%d] :> “_fmt”\n",_time_str,“Info”,FILE,LINE,##_X);
}
else if(_error_level
Debug)
{
fprintf(_fp,"[%s]-[%s]-[%s]-[%d] :> “_fmt”\n",_time_str,“Debug”,FILE,LINE,##_X);
}
fclose(_fp);
}
}while(0);

typedef int KeyType; //书号BookId类型

typedef struct Borrower{
int borrowerId; //借阅者图书证号
char name[20]; //借阅者姓名
time_t time; //归还时间
struct Borrower *next; //借阅者信息用链表
}BorrowerType; //借阅者类型

typedef struct {
char bookName[30]; //书名
char writerName[20]; //作者
char bookPress[30]; //出版社
int booknumNow; //现存量
int booknumAll; //总库存量
BorrowerType * borrower;
BorrowerType * booker;
}BookType; //文献类型

typedef struct BTNode{
int keynum; //结点当前的关键字个数
int key[m+1]; //索引数组,key[0]不用
struct BTNode* parent; //双亲结点指针
struct BTNode* ptr[m+1]; //孩子结点指针数组
BookType* books[m+1]; //书本数组,books[0]不用
}BTNode, *BTree;

typedef struct{
int index; //1<=index<=m,在结点中的关键字位序
int tag; //1:查找成功,0:查找失败
BTNode* node; //指向找到的结点
}result;

//图书管理的操作接口
void InsertBook(BTree &T, int k, BookType* book); //采编入库
void DeleteBook(BTree &t, KeyType key); //清除库存
void BorrowBook(result r,int number,char *name,int *flag); //借阅图书
int HasBorrow(result r,int number,char *name); //判断是否借过 0表示借过
int ReturnBook(result r, int number, char *name); //归还图书
void ShowBookAll(BTree t, KeyType key); //查看某种图书的信息(包括借阅者)
int SearchByWriter(BTree t,char *name, int *flag); //根据作者搜索书名
int SearchByBorrower(BTree t,int number,char *name, int *flag); //根据借阅者搜索书名
void ShowBook(BTree t, KeyType key); //输出某本书的信息
void addBook(BTree t, KeyType key, int num); //添加某本书的数量
int emtyBook(BTree q, int i); //检查某本书的现存量是否大于0
void TraverseBook(BTree t); //遍历输出所有文献信息
void Booking(result r,int number,char *name,int *flag);//预约文献
int CancelBooking(result r,BorrowerType *booker);//预约文献减去 1:成功
//界面展示
void Welcome(); //欢迎界面
void Choose(); //身份选择界面
int Login(); //管理员登录验证界面
void Menu_manager(); //管理员菜单
void Menu_borrower(); //借阅者菜单

//insert
void InitBTree(BTree &t); //初始化树
void InitBTNode(BTree &p); //初始化结点
int InsertBTree(BTree &T, int k, BookType* book); //插入结点
void split(BTree &q, BTree &ap); //分裂饱和结点
void newRoot(BTree &T, BTree p, BTree ap, int k, BookType* book); //创建新根结点
void Insert(BTree &q, int k, int index, BTree ap, BookType* book); //插入关键字及指针ap

//delete
int DeleteBTree(BTree &T, int key); //删除索引为key的记录
void Successor(BTree &node, int &index); //若不是终端结点,将直接前驱的索引和值覆盖掉当前结点
int Remove(BTree& node, int i); //从结点p中删除key[i]
int InsertBookType(BTree& node, int key,int i, BookType* book); //向父结点插入关键字
void Restore(BTree& node, int index); //调整树
void CombineBTNode(BTree& l_node, BTree& r_node); //合并结点
void DeleteRoot(BTree& root); //将合并后结点中所有记录插入到父节点中

//print
void Traverse(BTree t, int k); //遍历B树
void PrintBTree(BTree t); //打印B树

//search
void SearchBTree(BTree T, int k, result &r); //在m阶B树t上查找索引k,用r返回(pt,i,tag)
int Search(BTree p, int k); //在p->key[1…p->keynum]中查找p->key[i-1]<k<=p->key[i]

//data
void log_reocrd(int error_level, const char format, …); //日志记录
void Init(BTree &t); //读取图书文件
void Save(BTree &T);
void save_btree(BTree &T, FILE
fp);

display.cpp
#include “includes.h”

//管理员菜单
void Menu_manager()
{ now = time (NULL);
system(“cls”);
printf("\n ----------------------- 管理员系统 ---------------------- \n");

	printf("                                                  | 1 : 采编入库.       	|\n");

	printf("                                                  | 2 : 清除库存.       	|\n");

	printf("                                                  | 3 : 借阅文献.         	|\n");
	
	printf("                                               	  | 4 : 归还文献.       	|\n");
			
	printf("                                                  | 5 : 查看某种文献信息.       |\n");
	
	printf("                                                  | 6 : 输出B树的状态     	|\n");
	
	printf("                                                  | 7 : 输出所有文献.   	|\n");
	
	printf("                                                  | 8 : 按作者名查阅文献 . 	|\n");
	
	printf("                                                  | 9 : 根据借阅者输出文献.     |\n");		
	
	printf("                                                  | 10 : 返回主菜单.            |\n");
	
	printf("                                                  | 11 : 保存数据到文件.            |\n");
	
	printf("                                                  | 0 : 退出系统.               |\n");
	 
	printf("                                  -------------------------------------------------------------\n");
	printf("		                      当前时间:%s  ",ctime(&now) );
	printf("\n");
	printf("                                       **************请注意保存数据!************\n" );
	
	
}

//借阅者菜单
void Menu_borrower()
{
now = time (NULL);

system("cls");

printf("\n                                   -----------------------  借阅者系统 ---------------------- \n");                                                

printf("                                                         | 1 : 借阅文献. |\n");

printf("                                                         | 2 : 归还文献. |\n");

printf("                                                         | 3 : 查看某种文献的信息. |\n");

printf("                                                         | 4 : 输出B树的状态. |\n");

printf("                                                         | 5 : 输出所有文献. |\n");

printf("                                                         | 6 : 根据借阅者输出文献. |\n");

printf("                                                         | 7 : 按作者名查阅文献 . 	|\n");
	
printf("                                                         | 9 : 返回主菜单. |\n");

printf("                                                         | 10 : 保存数据到文件.      |\n");

printf("                                                         | 0 : 退出系统. |\n");

printf("                                     -------------------------------------------------------------\n");
printf("		                      当前时间:%s  ",ctime(&now) );

}

//欢迎界面
void Welcome()
{
now = time (NULL);

printf("\n\n\n\n\n");
printf("		\t╔══════════════════════════════════════════════════════════════╗\n");
printf("		\t║                                                              ║\n");
printf("		\t║                                                              ║\n");
printf("		\t║                 ._______________________.                    ║\n");
printf("		\t║                 | _____________________ |                    ║\n");
printf("		\t║                 | I                   I |                    ║\n");
printf("		\t║                 | I    文献管理系统   I |                    ║\n");
printf("		\t║                 | I                   I |                    ║\n");
printf("		\t║                 | I___________________I |                    ║\n");
printf("		\t║                 !_______________________!                    ║\n");
printf("		\t║                     ._[__________]_.                         ║\n");
printf("		\t║                 .___|_______________|___.                    ║\n");
printf("		\t║                  |:::  ____            |                     ║\n");
printf("		\t║                  |                     |                     ║\n");
printf("		\t║                  !_____________________!                     ║\n");
printf("		\t║                                                              ║\n");
printf("		\t║  制作者:计算机学院         20计科3班            张俊鸿      ║\n");
printf("		\t║                                                              ║\n");
printf("		\t║                                                              ║\n");
printf("		\t╚══════════════════════════════════════════════════════════════╝\n");
printf("		                      当前时间:%s  ",ctime(&now) );

}
//身份选择界面
void Choose()
{ now = time (NULL);
printf("\n\n\n");
printf(" \t╔══════════════════════════════════════════════════════════════╗\n");
printf(" \t║ ║\n");
printf(" \t║ ║\n");
printf(" \t║ ║\n");
printf(" \t║ ║\n");
printf(" \t║ ~~请选择你的身份 ║\n");
printf(" \t║ ║\n");
printf(" \t║ 1.管理员 ║\n");
printf(" \t║ ║\n");
printf(" \t║ ║\n");
printf(" \t║ 2.借阅者 ║\n");
printf(" \t║ ║\n");
printf(" \t║ ║\n");
printf(" \t║ 3.退出系统 ║\n");
printf(" \t║ ║\n");
printf(" \t║ ║\n");
printf(" \t║ ║\n");
printf(" \t║ ~~请你选择<1-3> ║\n");
printf(" \t║ ║\n");
printf(" \t║ ║\n");
printf(" \t╚══════════════════════════════════════════════════════════════╝\n");
printf(" 当前时间:%s “,ctime(&now) );
}
//管理员登录验证界面
int Login()
{
char pass[50];
char password[50]=“123456”; //设置管理员密码
printf(”\n\n\n\n\n\n\n\n");
printf("\t\t\t\t\t\t请输入管理员密码:\n");
printf("\n\n\n\n\n\n\n");
printf(" 请在此处输入:");
scanf("%s",pass);
if(!strcmp(pass,password)) //验证密码
{
printf("\n\n\n\n\n\n\n");
printf("=登录成功!\n");
Sleep(1500); //登陆延时程序,产生短暂的登陆状态
return 1;
}
else {
printf("\n\n\n\n\n\n\n");
printf("====密码错误!你没有管理员权限!\n");
Sleep(2000); //登陆延时程序,产生短暂的登陆状态
system(“cls”);
return -1;
}
return 0;
}

Data.cpp
#include “includes.h”

//日志记录
void log_reocrd(int error_level, const char *format, …)
{

va_list args;
FILE *fp=NULL;
char time_str[32];
char file_name[256];

va_start (args, format);
time_t time_log = time(NULL);
strftime(file_name,sizeof(file_name),"%Y-%m-%d_log_history.log",localtime(&time_log));

if((fp=fopen(file_name,"a+"))!=NULL)
{
    strftime(time_str,sizeof(time_str),"%Y-%m-%d %H:%M:%S",localtime(&time_log));
    if(error_level==(int)Error)
    {
        fprintf (fp, "[%s]-[%s]-[%s]-[%d] :> ",time_str,"ERROR",__FILE__,__LINE__);
        vfprintf (fp,format,args);
        fprintf (fp,"\n");

    }
    else if(error_level==(int)Waring)
    {
        fprintf (fp, "[%s]-[%s]-[%s]-[%d] :> ",time_str,"WARNINGs",__FILE__,__LINE__);
        vfprintf (fp,format,args);
        fprintf (fp,"\n");
    }
    else if(error_level==(int)Info)
    {
        fprintf (fp, "[%s]-[%s]-[%s]-[%d] :> ",time_str,"INFO",__FILE__,__LINE__);
        vfprintf (fp,format,args);
        fprintf (fp,"\n");
    }
    else if(error_level==(int)Debug)
    {
        fprintf (fp, "[%s]-[%s]-[%s]-[%d] :> ",time_str,"DEBUG",__FILE__,__LINE__);
        vfprintf (fp,format,args);
        fprintf (fp,"\n");
    }
    fclose(fp);
}

va_end (args);

}

//从文件中读取书本数据
void Init(BTree &t){
FILE r;
r= fopen(“BookData.txt”,“r”);
if(r==NULL){
printf(“打开文件失败!”);
exit(0) ;
}
BookType
book = (BookType *)malloc(sizeof(BookType));
book->borrower = NULL;
book->booker = NULL;
int key = 0;
while(fscanf(r,"%d %s %s %s %d %d",&key,book->bookName,book->writerName,book->bookPress,&book->booknumAll,&book->booknumNow)!=EOF)
{
InsertBTree(t,key,book);
book = (BookType *)malloc(sizeof(BookType));
book->borrower = NULL;
book->booker = NULL;
}
free(book);
book=NULL;
fclose®;
}

void Save(BTree &T){
FILE* fp = NULL;
if((fp = fopen(“BookData.txt”, “w”)) == NULL){
printf(“无法打开文件!\n”);
return;
}
save_btree(T, fp);
fclose(fp);
return;
}

void save_btree(BTree &T, FILE* fp){
if (T == NULL)return;
int i;
for (i = 0; i < T->keynum; i++){
save_btree(T->ptr[i], fp);
fprintf(fp, “%d %s %s %s %d %d\n”, T->key[i+1],
T->books[i+1]->bookName,
T->books[i+1]->writerName,
T->books[i+1]->bookPress,
T->books[i+1]->booknumNow,
T->books[i+1]->booknumAll);
}
save_btree(T->ptr[i], fp);
return;
}

Main.cpp
#include “includes.h”
time_t now;//系统时间

int main(int argc, const char** argv) {
system(“color 3e”); //背景淡蓝色

int c,a;		//c,a用于switch
int i,j;		//i,j用于循环
Welcome();			//欢迎界面 

system("pause");
system("cls");

BTree t;
InitBTNode(t);

// InitBTree(t);
Init(t);
loop:Choose(); //身份选择界面
printf(“请输入你的指令:”);
scanf("%d",&a);

result r;
while(a<1||a>3)			//用户错误输入后进行报错提示 
{
	printf("输入错误!请输入正确指令(1-3)\n");
	scanf("%d",&a);
	getchar();
}
system("cls");

if(a==1)	//管理员选项 
{	
LogRecord(Info,"进入管理员界面");
	j=Login();    //把Login返回值赋值给j	
	if(j==1)	//成功登录管理员 
	{ 	while(1)
		{ 
		LogRecord(Info,"进入管理员界面");
		Menu_manager();		//管理员菜单 
		printf("请输入你的指令:\n");
		i=scanf("%d",&a);
		if(i!=1)				//防止用户输入中文导致程序奔溃 
		{
		do{
			printf("输入错误,请输入正确指令(0-11)!\n");
			i=scanf("%d",&a);
			fflush(stdin);
		  }while(i!=1);
		}
		while(a< 0||a>11)			//用户错误输入后进行报错提示 
		{
			printf("输入错误!请输入正确指令(0-11)\n");
			scanf("%d",&a);
			getchar();
		}
		switch(a)
		{	
			case 1:			//采编入库
			{	
				LogRecord(Info,"采编入库");
				getchar();
				printf("********采编入库*********:\n");
                printf("请输入文献的编号\n");
                int bookId;
                scanf("%d", &bookId);
                SearchBTree(t, bookId, r);
                if (r.tag == 1) {
                    printf("此文献已存在\n");
                    ShowBook(t, bookId);
                    int bookNum1;
                    printf("请输入需要添加此文献的数量\n");
                    scanf("%d", &bookNum1);
                    addBook(t, bookId, bookNum1);
                }
                else {
                    printf("此文献不存在,\n");
                    char bookName[30], bookWriter[40], bookPress[40];
                    printf("请按顺序输入此文献的书名、作者、出版社(用空格隔开)\n");
                    scanf("%s%s%s", bookName,bookWriter,bookPress);
                    printf("请输入需要添加此文献的数量\n");
                    int bookNum2;
                    scanf("%d", &bookNum2);
                    BookType* newBook;
                    newBook = (BookType *)malloc(sizeof(BookType));
                    strcpy(newBook->bookName,bookName);
                    strcpy(newBook->writerName,bookWriter);
                    strcpy(newBook->bookPress,bookPress);
                    newBook->booknumAll = bookNum2;
                    newBook->booknumNow = bookNum2;
                    newBook->borrower = NULL;
                    InsertBook(t, bookId, newBook);
                }
                printf("添加完成!\n");
                ShowBook(t, bookId);
				system("pause");
				getchar();
				system("cls");
				break;	
			}	
            case  2 :		//清除库存 允许多次删除
			{	
				LogRecord(Info,"清除库存");
				getchar();
				printf("********清除库存*********:\n");
				printf("请输入文献的编号(输入0返回):\n");
				int key02;
		        scanf("%d", &key02);
				getchar();
				while(key02 != 0)
				{	
                    SearchBTree(t, key02, r);
                    if (r.tag == 0)
                        printf("此文献不存在!\n");
                    else {
                        ShowBook(t, key02);
                        printf("提示:清除后不可恢复!请确认是否清除:\n");
                        printf("  1:确认清除       0:取消  \n");
                        int a;
                        scanf("%d", &a);
                        if (a == 1) {
                            DeleteBook(t, key02);
                            printf("清除成功!\n");
                        }
                        else
                            printf("已取消\n");
                    }
					system("pause");
					getchar();
					printf("请输入文献的编号(不继续删除请输入 0 ):\n");
					scanf("%d", &key02);
				}
				system("cls");
				break;
			}	
			case 3:		//借阅文献
			{	
				LogRecord(Info,"借阅文献");
				getchar();
				printf("********借阅文献*********:\n");
		        printf("请输入文献的编号\n");
		        int key03;
		        scanf("%d", &key03);
		        SearchBTree(t, key03, r);
		        if(r.tag==0)
		            printf("此文献不存在!\n");
		        else {
		            ShowBook(t, key03);
		            if (emtyBook(r.node, r.index)){ 
		                printf("此文献现库存不足,是否选择预约!\n");
		                printf("1:是   0:否  \n");
		                int a0;
		                scanf("%d", &a0);
		                if(a0==1){
		                	printf("请输入借阅证号:\n");
		                    int q0;
		                    scanf("%d", &q0);
		                    printf("请输入您的姓名:\n");
		                    char name0[20];
		                    scanf("%s", name0, sizeof(name0));
		                    if(HasBorrow(r,q0,name0)) {
		                    	//先判断是不是他借的
								//是的话  return error 
			                    int flag0 = 0;
			                   	Booking(r, q0, name0,&flag0);
			                    if(flag0){
			                    	printf("预约成功!\n");
								}
							}
						}
		                //是否预约
						//预约链表加1 
						} 
		            else {
		                printf("请确认是否借文献:\n");
		                printf("1:确认   0:取消  \n");
		                int a;
		                scanf("%d", &a);
		                if (a == 1) {
		                    printf("请输入借阅证号:\n");
		                    int q;
		                    scanf("%d", &q);
		                    printf("请输入您的姓名:\n");
		                    char name[20];
		                    scanf("%s", name, sizeof(name));
		                    int flag = 0;
		                    BorrowBook(r, q, name,&flag);
		                    if(flag){
		                    	ShowBook(t, key03);
		                    	printf("借阅成功!\n");
							}
		                }
		                else
		                    printf("已取消\n");
		            }
			}
				system("pause");
				getchar();
				system("cls");
				break;
			}

			
			case  4 : 		//归还文献
			    {	
					LogRecord(Info,"归还文献");
				    getchar();
					printf("********归还文献*********:\n");
				    printf("请输入文献的编号\n");
				    int key04;
				    scanf("%d", &key04);
				    SearchBTree(t, key04, r);
				    if (r.tag == 0)
				        printf("此文献不存在!\n");
				    else {
				        ShowBook(t, key04);
				        printf("请确认是否归还:\n");
				        printf("1:确认   0:取消  \n");
				        int b;
				        scanf("%d", &b);
				        if ( b == 1) {
				            printf("请输入借阅证号:\n");
				            int q;
				            scanf("%d", &q);
				            printf("请输入您的姓名:\n");
				            char name[20];
				            scanf("%s", name, sizeof(name));
				            if (ReturnBook(r, q, name)) {
				            	BorrowerType *bookEr;
								bookEr = (BorrowerType *)malloc(sizeof(BorrowerType));
				            	while(CancelBooking(r,bookEr)){
				            		int flag03 = 0;
			                    	BorrowBook(r, bookEr->borrowerId, bookEr->name,&flag03);
			                    	printf("已将归还的书交给预约者 \n");
								}
				            	//while查看是否有人预约 
				            	//归还链表减一
								//将归还链表中的人自动借书 
				                ShowBook(t, key04);
				            }
				            else
				                printf("归还失败!查无对应的借阅者!\n");
				        }
				        else
				            printf("已取消\n");
				    }
					system("pause");
					getchar();
					system("cls");
					break;
				} 

			
			case  5 :		// 查看某种文献信息(包括文献借阅情况) 
			{	
				LogRecord(Info,"查看某种文献信息(包括文献借阅情况) ");
				getchar();
                printf("请输入文献的编号\n");
                int key05;
                scanf("%d", &key05);
                SearchBTree(t, key05, r);
                if (r.tag == 0)
                    printf("此文献不存在!\n");
                else {
                    ShowBookAll(t, key05);
                    
                }	
				system("pause");
				getchar();
				system("cls");
				break;
			} 
			
		 	case  6 : 		//输出B树的状态
			{	
				LogRecord(Info,"输出B树的状态");
                PrintBTree(t);
				system("pause");
				getchar();
				system("cls");
				break;
			}
			case  7 :		//输出所有文献 
			{	
				LogRecord(Info,"输出所有文献 ");
				getchar();
				printf("                   |-------------------------------------------------------------------------|\n");
				printf("                   |书号     书名           作者          出版社            现存量  总库存量 |\n");
				TraverseBook(t);
				system("pause");
				getchar();
				system("cls");
				break;	
			}
			case  8 : 		//按作者名查阅文献 
			{	
				LogRecord(Info,"按作者名查阅文献  ");
				getchar();
				int flag = 0;
				printf("请输入作者姓名:\n");
			    char name[20];
			    scanf("%s", name, sizeof(name));
				SearchByWriter(t,name,&flag);
				if(flag == 0)
					 printf("查无此作者相关文献!\n");
				system("pause");
				getchar();
				system("cls");
				break;
			}
			case 9 :		//根据借阅者搜索文献 
		    {	
				LogRecord(Info,"根据借阅者搜索文献");
		    	printf("请输入借阅证号:\n");
			    int q;
			    scanf("%d", &q);
			    printf("请输入您的姓名:\n");
			    char name[20];
			    scanf("%s", name, sizeof(name));
			    int flag = 0;
			    SearchByBorrower(t,q,name,&flag);
			    if(flag == 0)
					 printf("查无借阅记录!\n");
			    system("pause");
				getchar();
				system("cls");
			    break;
			}
			case  10:	//跳转回选择身份菜单 
			{
				system("pause");
				system("cls");
				goto loop;
			}
			case 11://保存数据到文件中
			{
				Save(t);
				printf("保存数据成功!");
				system("pause");
				getchar();
				system("cls");
				break; 
			 } 
			case  0 : 		//退出系统 
			{	printf("===================================================退出成功!==================================================\n");
				Sleep(500);	
				exit (0);
			}
			default:		
			{
				printf("请输入正确指令.\n");
				break;
			}

		}
		
		}
	}
} 

else if(a==2)		//选手菜单
{

while(1)
{		
		Menu_borrower();
		LogRecord(Info,"进入借阅者界面");
		printf("请输入你的指令:\n");
		i=scanf("%d",&a);
		if(i!=1)				//防止用户输入中文导致程序奔溃 
		{
		do{
			printf("输入错误,请输入正确指令!\n");
			i=scanf("%d",&a);
			fflush(stdin);
		  }while(i!=1);
		}
		while(a<0||a>11)
{
	printf("输入错误!请输入正确指令\n");
	scanf("%d",&a);
	getchar();
}
switch(a)
{
	
case 1:         //借阅文献
{	
	LogRecord(Info,"借阅文献");
	getchar();
	printf("********借阅文献*********:\n");
    printf("请输入文献的编号\n");
    int key03;
    scanf("%d", &key03);
    SearchBTree(t, key03, r);
    if(r.tag==0)
        printf("此文献不存在!\n");
    else {
        ShowBook(t, key03);
        if (emtyBook(r.node, r.index)){ 
            printf("此文献现库存不足,是否选择预约!\n");
            printf("1:是   0:否  \n");
            int a0;
            scanf("%d", &a0);
            if(a0==1){
            	printf("请输入借阅证号:\n");
                int q0;
                scanf("%d", &q0);
                printf("请输入您的姓名:\n");
                char name0[20];
                scanf("%s", name0, sizeof(name0));
                if(HasBorrow(r,q0,name0)) {
                	//先判断是不是他借的
					//是的话  return error 
                    int flag0 = 0;
                   	Booking(r, q0, name0,&flag0);
                    if(flag0){
                    	printf("预约成功!\n");
					}
				}
			}
            //是否预约
			//预约链表加1 
			} 
        else {
            printf("请确认是否借文献:\n");
            printf("1:确认   0:取消  \n");
            int a;
            scanf("%d", &a);
            if (a == 1) {
                printf("请输入借阅证号:\n");
                int q;
                scanf("%d", &q);
                printf("请输入您的姓名:\n");
                char name[20];
                scanf("%s", name, sizeof(name));
                int flag = 0;
                BorrowBook(r, q, name,&flag);
                if(flag){
                	ShowBook(t, key03);
                	printf("借阅成功!\n");
				}
            }
            else
                printf("已取消\n");
        }
}
	system("pause");
	getchar();
	system("cls");
	break;
}
case  2 : 		//归还文献
{	
	LogRecord(Info,"归还文献");
    getchar();
	printf("********归还文献*********:\n");
    printf("请输入文献的编号\n");
    int key04;
    scanf("%d", &key04);
    SearchBTree(t, key04, r);
    if (r.tag == 0)
        printf("此文献不存在!\n");
    else {
        ShowBook(t, key04);
        printf("请确认是否归还:\n");
        printf("1:确认   0:取消  \n");
        int b;
        scanf("%d", &b);
        if ( b == 1) {
            printf("请输入借阅证号:\n");
            int q;
            scanf("%d", &q);
            printf("请输入您的姓名:\n");
            char name[20];
            scanf("%s", name, sizeof(name));
            if (ReturnBook(r, q, name)) {
            	BorrowerType *bookEr;
				bookEr = (BorrowerType *)malloc(sizeof(BorrowerType));
            	while(CancelBooking(r,bookEr)){
            		int flag03 = 0;
                	BorrowBook(r, bookEr->borrowerId, bookEr->name,&flag03);
                	printf("已将归还的书交给预约者 \n");
				}
            	//while查看是否有人预约 
            	//归还链表减一
				//将归还链表中的人自动借书 
                ShowBook(t, key04);
            }
            else
                printf("归还失败!查无对应的借阅者!\n");
        }
        else
            printf("已取消\n");
    }
	system("pause");
	getchar();
	system("cls");
	break;
} 

case  3 :		// 查看某种文献信息
{	
	LogRecord(Info,"查看某种文献信息");
	getchar();
    printf("请输入书的编号\n");
    int key05;
    scanf("%d", &key05);
    SearchBTree(t, key05, r);
    if (r.tag == 0)
        printf("此书本不存在!\n");
    else {
        ShowBook(t, key05);
        
    }	
    system("pause");
    getchar();
    system("cls");
    break;
} 
case  4 : 		//输出B树的状态
{	
	LogRecord(Info,"输出B树的状态");
    PrintBTree(t);
    system("pause");
    getchar();
    system("cls");
    break;
}

case  5 :		//输出所有文献 
	{	
		LogRecord(Info,"输出所有文献 ");
		getchar();
		printf("                   |-------------------------------------------------------------------------|\n");
		printf("                   |书号     书名           作者          出版社            现存量  总库存量 |\n");
		TraverseBook(t);
		system("pause");
		getchar();
		system("cls");
		break;	
	}
	
case 6 :		//根据借阅者搜索文献 
{	
	LogRecord(Info,"根据借阅者搜索文献 ");
	printf("请输入借阅证号:\n");
    int q;
    scanf("%d", &q);
    printf("请输入您的姓名:\n");
    char name[20];
    scanf("%s", name, sizeof(name));
    int flag = 0;
    SearchByBorrower(t,q,name,&flag);
	if(flag == 0)
		printf("查无借阅记录!\n");
    system("pause");
	getchar();
	system("cls");
    break;
}
	case  7 : 		//按作者名查阅文献 
{	
	LogRecord(Info,"按作者名查阅文献  ");
	getchar();
	int flag = 0;
	printf("请输入作者姓名:\n");
    char name[20];
    scanf("%s", name, sizeof(name));
	SearchByWriter(t,name,&flag);
	if(flag == 0)
		 printf("查无此作者相关文献!\n");
	system("pause");
	getchar();
	system("cls");
	break;
}
case 9:				//返回选择菜单界面 
{
	system("pause");
	system("cls");
	goto loop;
}
case 10://保存数据到文件中

{
Save(t);
printf(“保存数据成功!”);
system(“pause”);
getchar();
system(“cls”);
break;
}
case 0: //退出系统
{
printf("=成功退出系统\n");
Sleep(500);
return 0 ;
}
default:
{
printf(“请输入正确指令.\n”);
break;
}

}

} 
}

getchar();
return 0;

}
四、调试分析
1.遇到的问题及分析
(1) 预约功能的实现
在图书的现存量不足时,再次借阅应进行预约,在本例中,对于预约功能,新增booker链表,当有人归还时则将归还的书给到预约者,实现预约文献功能。
(2) 日志功能的实现
真正的日志实现应保持四类数据:Error,Waring,Info,Debug,但是由于模拟日志,本例只能实现INFO日志的打印,在进行基本操作时将信息以【时间】+【Info】+【文件名】+【函数】+【日志信息】打印
(3) 变内存为文件存储
本系统一开始的设计只实现使用链表与B树内存运行,无法存储每次运行的信息,即进行读档存档,后添加文件(BookData.txt)实现文件初始化读取以及系统信息的保存
2.算法的时空分析
B 树基本操作 时间复杂度
SearchBTree(BTree T, int k, result &r); O(logn)
InsertBTree(BTree &T, int k, Record rcd); O(logn)
DeleteBTree(BTree &T, int key); O(logn)
Traverse(BTree t, int k); O(logn)
PrintBTree(BTree t); O(logn)

3.经验和体会
①课程设计应按照实验书上的步骤一步一步来,先明确自己的需求分析,再进行概要设计,明确各数据类型的定义(包括存储结构定义等),主程序流程和各程序模块之间的调用关系。只有对模块设计有了大致思路,写代码的时候思路才会更加清晰,切忌不要写一步想一步。
②使用的 devc++ 中的源文件格式是“.cpp”,应注意 C++与 C 的区别和联系。
③根据之前的设计分析将程序划分成几个模块,单独编写每个模块的基本操作
(新建多个源文件)再组合在一起,会降低设计的难度,也方便调试。
④本系统的界面显示停留在简答的printf,如果可以使用C#设计图形化界面,将会更加美观
五、用户使用说明
编程环境:DecC++
编程语言:C
程序入口:文献管理系统.exe
管理员密码:123456
(一) 初始欢迎界面

可显示系统时间
(二) 用户身份选择界面

(三) 管理员界面

(四) 借阅者界面

(五) 以管理员界面为例详解
可输入【0-11对于不同功能】
 功能1【采编入库】:输入文献编号,若不存在,则按顺序输入书名 作者 出版社;若已存在,则输入需要添加文献的数量
 功能2【清除库存】:输入文献编号,若文献存在,则进行确认,确认完毕清除该文献库存
 功能3【借阅文献】:输入文献编号,若文献存在且现存量足够,则确认是否借阅,输入借阅证号和借阅姓名;若文献无库存,则进行预约,输入借阅证号和预约姓名
 功能4【归还文献】:输入文献编号,若文献存在,则输入借阅证号和借阅姓名,判断是否借阅过,以及是否按期归还,若存在预约者,则将文献移交给预约者。
 功能5【查看某种文献信息】:输入文献编号,若文献存在,输出文献的书号,书名,作者,出版社,现存量,总库存量,若为管理员,还可输出借阅者信息
 功能6【输出B树的状态】:以凹入表形式打印文献书号
 功能7【输出所有文献】:输出系统中所有文献的书号,书名,作者,出版社,现存量,总库存量
 功能8【按作者名查阅文献】:输入作者名,若存在按作者名进行搜索文献并打印出
 功能9【俺借阅者输出文献】:输入借阅证号和借阅者姓名,若存在,则按借阅者名进行搜索文献并打印出
 功能11【保存数据到文件】:将当前系统的数据保存到【BookData.txt】中进行存档
六、测试结果
测试数据如下:(以下数据仅为测试编写,与原书名和作者无关)

书号 书名 作者名 出版社 现存量 总库存量
1 1 1 1 2 2
3 电路第5版 邱关源 高等教育出版社 5 5
7 电工学下册 刘成悦 复旦大学出版社 85 85
10 计算机科学概论 张爱红 高等教育出版社 59 59
12 专业实验基础 朱平 电子工业出版社 5 5
13 半导体物理 旭里 吉林大学出版社 64 64
14 简明大学物理学 范仰才 高等教育出版社 6 6
16 概率论与数理统计 微电子系 高等教育出版社 73 73
17 大学物理学上册 范仰才 北京大学出版社 41 41
20 政治 张俊鸿 广告稿 555 555
21 C语言程序设计 王绵森 北京大学出版社 40 40
27 高等数学上册 同济大学数学系 广东工业大学出版社 47 47
35 数据结构 吴伟民 高等教育出版社 1 1
42 高等数学下册 同济大学数学系 广东工业大学出版社 50 50
45 离散数学及其应用 傅彦 化学工业出版社 40 40
54 电工与电子技术实验教程 彭端 北京大学出版社 12 12
62 复变函数第二版 刘恩科 高等教育出版社 51 51
71 大学物理实验 朱道云 高等教育出版社 87 87
88 电工学上册 苏林 高等教育出版社 87 87
90 线性代数 同济大学数学系 高等教育出版社 98 98
打开程序,初始欢迎界面如下:显示系统时间

进入身份选择界面
管理员界面
进行身份验证才可进行,实现登录延时

进入借阅者界面

对管理员界面进行功能测试
 采编入库测试
文献存在

文献不存在

 清除库存
可检测文献是否存在
可循环清除直到不清除

 借阅文献
可借阅,可预约

同一个人不可重复借阅

现存量不足时其他借阅者可以预约

 归还文献
规划时若有预约自动将文献借给预约者
可根据归还时间进行归还判断是否延期,此处可进行拓展:如扣除信誉分等等

 查看某文献信息【管理员可查看借阅信息】

 输出B树的状态

 输出所有文献

 按作者名查阅文献

 根据借阅者输出文献

 保存数据到文件

 将程序运行的操作记入日志文件中

显示时间 Info 文件名 行数 日志信息
 返回主菜单

 退出系统

七、附录
程序文件名清单
 includes.h
 book.cpp
 data.cpp
 delete.cpp
 display.cpp
 insert.cpp
 insert.cpp
 main.cpp
 print.cpp
 search.cpp

举报

相关推荐

0 条评论