资源描述
______________________________________________________________________________________________________________
湖南科技大学
课程设计报告
题目: 图书管理基本业务模拟
院 系:计算机科学与工程学院
专业班级:计算机科学与技术一班
学 号: 0905010119
学生姓名: 张 杰
指导教师: 李 峰
2010年12月31日
一、 问题分析
图书馆基本业务模拟包含多方面的操作,其中本程序描述的是图书馆的新书入库、读者注册、图书馆借阅、归还、信息查询(含书籍信息查询和读者信息查询)等功能。
1) 新书入库功能:
新到书籍入库包含几方面的操作:查询该书名的书籍在图书馆信息中是否已经存在,若存在,则增加可借数量和书籍总量,若不存在,则新增加概述信息,从界面输入书籍的编号(0~999999的长整型)、书名(字符串类型)、该书作者名(字符串类型)、该书出版社信息(字符串类型)、出版日期(长整型)、该书的现存量(整型)、该书的总量(整型)。输入该信息之后,将该节点插入到书籍信息链表中去。该节点的插入位置根据查找,找到合适的位置插入,这样可以保证整个数据都是有序的,方便查找。
2) 读者注册功能
没有账号和密码读者和管理员都不能登录系统,本系统默认第一个注册系统的是系统管理员,借阅号为1000,权限是1,并输入自己基本信息,默认可借本数为10,并将所借书信息区全部置零。不是第一个注册的读者,借阅号从1000往后顺延,自己设置密码,权限为0.,其余信息与管理员相同,但是登陆之后的界面,管理员可以看到“入库”菜单选项,普通读者不能看到该选项。
3) 借阅功能
书籍借阅主要涉及存书库和读者信息库双方的更新。用户首先登陆系统,查询(3种查询方式)该书是否存在,该书的剩余数量是否大于零,最后查询该读者是否已经借满书籍。若以上条件都满足,则将该书编号存入该读者的借阅信息区,将该读者的可借书数量减一,该存书的可借数量减一。
4) 归还功能
读者登录后按书名号来归还所借书籍,若书名号正确并且确认归还该书籍,则从读者的借书区删除该书籍,读者的课结束数量加一,将该书的可借数量增加一,然后返回。
5) 信息查询功能
信息查询分为读者信息查询和书籍信息查询,读者信息查询是在读者登录之后,可以显示本人的基本信息以及借书状况(所借书的本数、可借书本书以及所借书的信息),还可查询书籍信息,可根据书籍的编号来查找书籍、根据书名来查找书籍、根据作者名来查询书籍。查询到该书籍后显示是否借阅该书籍。
二、 数据结构描述
根据所给信息,可以采用线性链表来实现该问题。现在分别给予描述。
1) 读者
读者有很多信息需要使用,其中包含读者的姓名、性别、密码、权限、所借书信息。这里我们定义一个结构体来描述他。定义的结构体代码如下:
typedef struct READER{
long number;//借阅号
char name[15];//读者姓名
char sex;//读者性别
char password[16];//读者的密码
int residue;//读者的剩余可借书籍数量
long borrowed[10];//读者已经借阅的书籍编号
int limit;//读者权限
struct READER *next;//该结构体作为线性链表的一部分用来链接下一个节点的指针
}reader;
2) 书籍
同读者信息一样,书籍也有很多信息需要描述,其中包含书籍的编码、书名、书籍作者、书籍的总量、书籍的可借数量、出版社信息、出版日期,整个全部我们定义一个reader类型的结构体,该结构体定义的代码如下:
typedef struct BOOK{
long number;//书籍编号
char name[30];//书名
char author[30];//作者
char press[30];//出版社信息
long presstime;//出版日期
int exist;//在库数量
int total;//总数量
struct BOOK *next;//指向写一个节点的指针
}book;
3) 数据链接
数据通过每个节点的“next”指针来链接,是单线性链表,只可以从头部查询数据,所以要记录好该链表的头结点位置,不要拿该节点的头结点参与运算,否则在程序中可能会修改该链表的头结点的信息,导致后续程序无法运行。
4) 查询
查询书籍分为按书名查询、按书号查询和按作者查询。按书名查询到的书籍我们设定为是唯一的,及整个书库中只有一种叫该名的书籍。根据输入的书籍名,从书籍信息链表的首元节点开始遍历,若查找到则返回该书籍的指针,若没找到,则返回NULL。按作者查询的书籍可能不止一种,一样从头结点开始遍历数据,每查到一个,则输出该书信息,并且继续往下查询,该函数没有返回者,读者可以根据查询到的数据,记下编号或者书名来进一步确认该书籍信息,然后借阅该书籍。按书号查询,书号作为KEY值,在书籍里面是独一无二的,我们建立一个索引表,每两个key之间有5本书籍,这样根据所查书籍的书号可以确认该书在那个大概的区段,但后从该区段的首地址往下搜索最多5次便可确认该书的位置或者确认该书是否存在于该书库中。
查询读者信息读者登录之后可以查阅自己信息,从读者头结点开始往下查询,若查询到该读者,则返回该读者指针,并且显示该读者信息,若没有查找到,则返回NULL。
图书馆管理系统
注册
登陆
个人信息
借阅
入库
归还
个人信息
归还
A、借阅模块:
函数声明:void borrow(reader *temp,book*Bhead);//借书
说明:Temp是该读者的指针,Bhead是该书籍链表的头指针。该函数的流程图如下:
N
进入查找
按书名查找
按书号查找
按作者查找
进入借阅
输入书名
继续借阅
退出借阅
输入书号
输入作者
未找到
找到
借阅
找到
借阅成功
找到
Y
N
Y
Y
N
B、归还模块
函数声明:void returnbook(book*bhead,reader *temp);//还书
说明:bhead是书籍链表的头指针,temp是借阅者的指针。流程图如下:
进入归还
输入书号
存在
归还
归还成功
退出归还
Y
N
Y
N
C、插入模块
函数声明: void insert(book*bhead);//入库
说明:bhead是书籍链表的头指针,流程图如下:
开始入库
输入书号
N
N
书号合格
输入书籍信息
Y
Y
继续输入
结束输入
三、 算法设计
1、 读者信息存储
读者信息采用线性单链表存储,设置头结点,头结点不存储数据,初始化时头结点->next设置为空,然后每从文件中读取一组数据,则将该数据存入新开辟的空间,链接到读者信息链表中,再将该数据的next置空。
2、 书籍信息存储
书籍信息存储采用单链表存储,设置头结点,头结点不存储数据,头结点的next为空,初始化时,从文件中读取一个格式化的数据,则将该数据存入新开辟的空间,并将该节点链接到链表中去,将next置空。
3、 查找
查找分按书名查找、按作者查找和按书号查找。按书名查找是采用遍历线性链表的方式,从首元结点开始向下遍历,检查输入的书名和已存的书名是否匹配,如果匹配,则将该书籍的指针返回,然后查找结束。若直到最后也没找到,则返回空。按作者查找则根据输入的作者名,从书籍链表的首元结点开始遍历,检查记录中的读者信息和输入的是否匹配,若找到匹配的,则输出该书籍信息,然后继续向下遍历,直到链表尾部,查找结束。按书号查找则是根据建立的索引表来查找记录。
索引表是一个线性单链表,每个索引节点包含3个内容:该索引的key值、该key值指向的书籍节点、该索引节点的下一个索引节点所在的位置。设定书籍链表中每5本书籍取一个key值,从书籍链表的首元结点开始。索引链表的头结点也为空,首元结点存储书籍链表的第一个记录的书号、第一个节点的位置和下一个索引节点的位置。然后按书号查找时,先查找索引表,找到最近的入口,再从索引节点进入书籍节点,查找到该书籍,返回该书籍的指针。按索引表在较大的数据查询时可以用空间换时间的方式减少查询时间,达到提高效率的结果。但是这样分配新的节点需要占用空间,而且每次有新增书籍需要重新生成索引表,这样需要删除源节点空间,以免造成内存浪费。
四、 详细程序清单
1、 头文件定义
头文件library.h定义了3个结构体:书籍结构体、读者结构体和索引表结构体,其中书籍结构体和索引表结构体已经给出,这里不再赘述,索引表结构体的定义如下:
typedef struct KEY{//索引表结点
long key;
book *adress;
struct KEY *next;
}keynode;
头文件还包含一些系统头文件的声明:
#include"stdio.h"
#include"string.h"
#include"conio.h"
#include"windows.h"
还有一些函数的声明,用#ifndef、#endif来包含,以免重复包含。
2、 插入部分
插入部分分为书籍入库、读者注册、登陆3大块,分3个函数,声明如下:
void insert(book*bhead);//入库
void reg(reader*head);//注册
reader* login(reader*rhead,book*bhead);//登陆
这3个函数分别实现新书入库、读者注册、登陆等功能,入库功能只有管理员才能调用,其余函数均可以调用,在主函数界面就可以。
3、 读写模块
此模块主要实现向文件写入、读取数,主要是2个文件:reader.txt、book.txt,分为4个函数:读者读、写函数,书籍读、写函数。定义如下:
book* Bload();//书籍链表读取
reader*Rload();//读者链表读入
void Bsave(book*Bhead);//书籍信息链表写入
void Rsave(reader*Rhead,book*bhead);//读者信息链表写入
读者和书籍链表的初始化就由读取函数完成,若文件为空则返回空指针,若不为空,则将文件里面的信息写入到链表中,每读出一个数据,分配一个空间,将该信息输入。
4、 查找模块
查找模块分书籍查找模块、读者查找模块,书籍查找模块分线性链
遍历查询、索引表查询,读者查询直接遍历读者链表,查找该读者,若存在,返回指针,不存在则返回NULL。查找模块的定义如下:
book*S_name(book*head,char name[]);//按书籍名查找函数
void S_author(book*head);//按作者查找
keynode*initindex(book*head);//初始化建立索引表
book*S_number(long num,book*bhead);//按书号查找
reader*S_reader(reader*rhead,long num);//查找读者
5、 显示模块
根据给出的节点指针,显示该节点所包含的信息,显示分为读者显示和书籍信息显示,读者信息显示包含书籍信息显示,以便显示读者所借书的信息。这两个函数的声明如下:
void showR(reader*tr,book*bhead);//显示读者信息函数
void showB(book*p);//显示书籍信息函数
这个模块还有2个小函数,用于将存入的性别’F’、’M’转化成汉字,将存的权限“1”、“0”转化成“管理员”、“读者”输出,这两个函数的定义如下:
char*sc(char p)
{
if(p=='F'||p=='f')
return "女";
else
return "男";
}
char*lc(int i)
{
if(i==1)
return "管理员";
else
return "读者";
}
6、 风格函数
Style()这个函数用来设置运行的界面颜色,并调用时执行清屏。还有密码保护函数,这个函数可以保护输入的密码不显示在界面上,不被别人看到,这个函数的定义如下:
void intpsd(char *psd)//密码保护函数
{int i=0; char c;
while((c=getch())!=13) /*用getch()读入的回车值为13*/
{if (c!='\b' && c!='\t' && i<20)
{psd[i]=c; putchar('*'); i++; }
if (c=='\b' && i>0)
{printf("\b \b"); i--; } /*输出内容为退格,空格,退格;擦掉一个字符*/
}
psd[i]='\0';
return;
}
这个模块还有几个菜单界面,不再赘述。
五、 程序运行结果
1、 登陆界面
2、 入库界面
3、 借阅界面
4、 还书界面
六、 心得体会
这个程序设计大作业相对去年的程序设计大作业来说,难度有所提高,主要是使用了一些数据的处理方法,在数据的存储、调用、查找、排序灯方面都得到了充分的锻炼,巩固了数据结构的基本知识,加深了对C语言知识的巩固,并尝试了一些新的想法和思路,在整个程序设计过程中收获颇多。在处理数据和程序代码方面都得到了很大的锻炼。
这次课程设计使我看到了很多不足,主要是对语言还理解不够透彻,一知半解等现象,也没有做出很漂亮的界面来支撑程序,而且个人感觉有些凌乱。
总之,这次程序设计大作业,感受颇多,今后还要继续努力!
七、 参考文献
[1]严蔚敏, 吴伟民. 数据结构(C语言版).北京:清华大学出版社,2010.3
[2] 蒋清明,黄晓宇,向德生等. C语言程序设计. 北京:人民邮电出版社,2008.4
[3]李春葆等.数据结构教程(C语言版)。北京:清华大学出版社,2005.1
源码:
1、 library.h
#ifndef LIBRARY_INCLUDE//条件编译 防止重复包含
#define LIBRARY_INCLUDE
#include"stdio.h"
#include"string.h"
#include"conio.h"
#include"windows.h"
#include"time.h"
typedef struct BOOK{
long number;
char name[30];
char author[30];
char press[30];
long presstime;
int exist;
int total;
struct BOOK *next;
}book;
typedef struct KEY{
long key;
book *adress;
struct KEY *next;
}keynode;
typedef struct READER{
long number;
char name[15];
char sex;
char password[16];
int residue;
long borrowed[10][2];
int limit;
struct READER *next;
}reader;
//以下是函数声明
char*lc(int i);//将权限转换成可显示易理解的汉字
char*sc(char p);//将性别转换成可现实易理解的文字
void showR(reader*tr,book*bhead);//显示读者信息函数
void showB(book*p);//显示书籍信息函数
book*S_name(book*head,char name[]);//按书籍名查找函数
void S_author(book*head);//按作者查找
keynode*initindex(book*head);//初始化建立索引表
void delkey(keynode*keyhead);
book*S_number(long num,book*bhead);//按书号查找
reader*S_reader(reader*rhead,long num);//查找读者
book* Bload();//书籍链表读取
reader*Rload();//读者链表读入
void Bsave(book*Bhead);//书籍信息链表写入
void Rsave(reader*Rhead,book*bhead);//读者信息链表写入
void insert(book*bhead);//入库
void reg(reader*head);//注册
reader* login(reader*rhead,book*bhead);//登陆
void borrow(reader *temp,book*Bhead);//借书
void returnbook(book*bhead,reader *temp);//还书
void style();//风格函数
void intpsd(char *psd);//密码保护函数
void menu(struct BOOK*Bhead,reader*Rhead);//菜单
void menu2(reader*temp,reader*rhead,book*bhead);
long backtime();//结束时间
#endif
2、 borrow_return.cpp
#include"library.h"
//借阅
void borrow(reader *temp,book*Bhead)
{
style();
long num;
int i;
char t,k,name[30];
book*Bbook;
while(1)
{
printf("\n ┏━━━━━━━━━━┓ ");
printf("\n█━━━━━━━━━━━┫ 欢迎使用 借阅系统 ┣━━━━━━━━━━━█");
printf("\n ┗━━━━━━━━━━┛ ");
printf("\n请输入您要查找借阅书籍的方式:");
printf("\n 1、按书号查找\n");
printf("\n 2、按作者查找\n");
printf("\n 3、按书名查找\n");
printf("\n 4、返回主菜单\n");
t=getch();
switch(t)
{
case '1':
{
printf("\n请输入您要查找的书籍编号:");
scanf("%d",&num);
if((Bbook=S_number(num,Bhead))!=NULL)
{
showB(Bbook);
printf("\n请问你是否要借阅该书籍?Y/N");
k=getch();
if(k=='Y'||k=='y')
goto borrow;
else
break;
}
else
break;
}
case '2':
{
S_author(Bhead);
break;
}
case '3':
{
printf("\n请输如您要查找的书籍名:");
scanf("%s",name);
if((Bbook=S_name(Bhead,name))!=NULL)
{
showB(Bbook);
printf("\n请问你是否要借阅该书籍?Y/N");
k=getch();
if(k=='Y'||k=='y')
goto borrow;
else
break;
}
else
continue;
break;
}
default:
return;
borrow: if(Bbook!=NULL&&temp->residue>0&&Bbook->exist>0)
{
temp->residue--;
Bbook->exist--;
for(i=0;i<10;i++)
{
if(temp->borrowed[i][0]==0)
{
temp->borrowed[i][0]=Bbook->number;
temp->borrowed[i][1]=backtime();
break;
}
}
printf("\n 借阅成功!");
}
else
if(!(temp->residue>0))
printf("\n您只能借阅10本书籍!");
else
if(!(Bbook->exist>0))
printf("\n该书没有库存,请借阅其他书籍!");
printf("\n您要继续借阅书籍吗?Y/N");
t=getch();
if(t=='y'||t=='Y')
continue;
else
break;
}
}
}
void returnbook(book*bhead,reader *temp)//还书
{
long num;
int i,j=0;
char t;
book*p;
printf("\n ┏━━━━━━━━━━┓ ");
printf("\n█━━━━━━━━━━━┫ 欢迎使用 还书系统 ┣━━━━━━━━━━━█");
printf("\n ┗━━━━━━━━━━┛ ");
printf("\n\n请输入您所还书的编号:");
scanf("%d",&num);
for(i=0;i<10;i++)
{
if(num==temp->borrowed[i][0])
j=1;
}
p=S_number(num,bhead);
if(p!=NULL&&j==1)
{
printf("\n┌────┬──────┬───────┬────┬───────┐");
printf("\n│书本编号│ 书籍名称 │ 出版社名称 │出版时间│ 作者 │");
printf("\n├────┼──────┼───────┼────┼───────┤");
printf("\n│%8d│%12s│%14s│%8d│%14s│",p->number,p->name,p->press,p->presstime,p->author);
printf("\n└────┴──────┴───────┴────┴───────┘\n");
printf("\n确认归还该书籍?Y/N");
t=getch();
if(t=='Y'||t=='y')
{
p->exist++;
temp->residue++;
for(i=0;i<10;i++)
{
if(temp->borrowed[i][0]==num)
{
temp->borrowed[i][0]=0;
temp->borrowed[i][1]=0;
break;
}
}
}
else return;
}
else
{
printf("\n编号有误,请仔细检查!");
}
}
3、 insert.cpp
#include "library.h"
void insert(book*bhead)//入库
{
style();
long t;
book*temp1,*temp,*temp2;
temp1=bhead->next;
printf("\n ┏━━━━━━━━━━┓ ");
printf("\n█━━━━━━━━━━━┫ 欢迎使用 入库系统 ┣━━━━━━━━━━━█");
printf("\n ┗━━━━━━━━━━┛ ");
while(1)
{
printf("\n请输入您给定书的编号(6位以内的正整数):");
scanf("%d",&t);
if(t<=0||t>999999)
{
printf("\n您的编号不在处理范围(1~999999)之内!");
fflush(stdin);
continue;
}
else
{
temp2=S_number(t,bhead);
if(temp2==NULL)
{
break;
}
else
{
temp2->total++;
temp2->exist++;
printf("\n编号为%d的书已存在,入库成功!",t);
return;
}
}
}
temp=(book*)malloc(sizeof(book));
temp->number=t;
printf("\n请输入书名:");
scanf("%s",temp->name);
printf("\n请输入本书作者:");
scanf("%s",temp->author);
printf("\n请输入本书出版社:");
scanf("%s",temp->press);
printf("\n请输入本书出版时间:");
scanf("%d",&temp->presstime);
temp->next=NULL;
temp->total=1;
temp->exist=1;
if(bhead->next==NULL)
bhead->next=temp;
else
{
while(temp1->next!=NULL&&temp1->number<temp->number)//找到合适的位置,插入书籍信息
temp1=temp1->next;
temp->next=temp1->next;
temp1->next=temp;
}
printf("\n ┏━━━━━━━━━━┓ ");
printf("\n█━━━━━━━━━━━┫ 入库成功 ┣━━━━━━━━━━━█");
printf("\n ┗━━━━━━━━━━┛ ");
}
void reg(reader*head)//注册
{
style();
long i=1000;
int j;
char t1[16],t2[16];
reader *temp=head->next;
reader *p=(reader*)malloc(sizeof(reader));
printf("\n ┏━━━━━━━━━━┓ ");
printf("\n█━━━━━━━━━━━┫ 欢迎使用 注册系统 ┣━━━━━━━━━━━█");
printf("\n ┗━━━━━━━━━━┛ ");
printf("\n 请输入姓名:");
scanf("%s",p->name);
getchar();
while(1)
{
printf("\n 请输入性别:\n M:男性:\n F:女性:");
p->sex=getchar();
if(p->sex=='F'||p->sex=='f'||p->sex=='M'||p->sex=='m')
break;
else
printf("\n 阁下既非男,又非女,莫非来自泰国?");
}
while(1)
{
while(1)
{
printf("\n 请输入您的密码:");
intpsd(t1);
if(strlen(t1)<=4)
printf("\n 您设置的密码过于简单,请重新设置:");
else
break;
}
printf("\n 请确认您的密码:");
intpsd(t2);
if(strcmp(t1,t2)==0)
{
strcpy(p->password,t1);
break;
}
else
printf("\n 您两次输入的密码不一致!");
}
p->residue=10;
p->next=NULL;
for(j=0;j<10;j++)
{
p->borrowed[j][0]=0;
p->borrowed[j][1]=0;
}
if(temp==NULL)
{
p->number=i;
head->next=p;
p->limit=1;
}
else
{
++i;
while(temp->next!=NULL)
{
++i;
temp=temp->next;
}
p->number=i;
p->limit=0;
temp->next=p;
}
showR(p,NULL);
}
reader* login(reader*rhead,book*bhead)//登陆
{
long num;
char pass[16];
int i=5;
reader*reader;
style();
printf("\n ┏━━━━━━━━━━┓ ");
printf("\n█━━━━━━━━━━━┫ 欢迎使用 登陆系统 ┣━━━━━━━━━━━█");
printf("\n ┗━━━━━━━━━━┛ ");
while(1)
{
printf("\n 请输入您的借阅证号:");
scanf("%d",&num);
if((reader=S_reader(rhead,num))==NULL)
{
printf("\n 没有找到您所在编号的读者.");
getch();
return NULL;
}
else
break;
}
while(i>0)
{
printf("\n 请输入密码:");
intpsd(pass);
if(strcmp(pass,reader->password)==0)
return reader;
else
{
printf("\n 密码错误");
return NULL;
}
}
}
4、 load_save.cpp
#include "library.h"
book* Bload()//书籍链表读取
{
FILE *p;
book*Bhead=(book*)malloc(sizeof(book));
book*temp,*temp1;
Bhead->next=NULL;
if((p=fopen("book.txt","r"))==NULL)
{
printf("\n打开文件book.txt失败,请检查...");
return NULL;
}
else
{
fgetc(p);
if(!feof(p))//未到文件尾
{
printf("\n非空");
rewind(p);//返回文件头
temp=(book*)malloc(sizeof(book));
fscanf(p,"%14d%12s%18s%8d%14s%4d%4d\n",&temp->number,temp->name,temp->press,&temp->presstime,temp->author,&temp->total,&temp->exist);
temp->next=NULL;
Bhead->next=temp;
}
while(!feof(p))
{
展开阅读全文