目录
基于线性表的图书管理系统实验报告
1、成员分工
2、数据字典
3、抽象数据类型定义
4、图书存储结构描述
5、基本操作的算法描述
6、测试
6.1测试数据集
6.2测试程序运行结果截图
7、存在的问题与思考
基于线性表的图书管理系统实验报告
组长:xxx
组员:xxx、xxx、xxx、xxx
1、成员分工
姓名 | 分工 |
xxx | 编写主要代码,测试 |
xxx | 编写主要代码,测试 |
xxx | 编写与修改代码、实验报告整理 |
xxx | 实验报告整理、编写测试数据 |
2、数据字典
序号 | 字段名 | 类型 | 说明 |
1 | ISBN | String | 图书号 |
2 | name | String | 图书名称 |
3 | author | String | 图书作者 |
4 | publish | String | 图书出版社 |
5 | date | String | 图书出版日期 |
6 | price | Double | 图书价格 |
7 | type | String | 图书类型 |
8 | ison | String | 图书状态:在架上、已订阅、正在订购 |
3、抽象数据类型定义
数据元素:可以是任意类型,只要属同一个数据对象即可
数据关系:数据元素之前呈现行关系,假设线性表中有n个元素(a1,a2,a3,···,an),则对每个元素ai(i=1,2,···,n-1)都存在关系(ai,ai+1),并且a1无前驱,an无后继。
数据操作:将对线性表的基本操作定义在接口Comparable<book>中,代码如下:
//book类
class book implements Comparable<book> {
String getISBN();//返回图书ISBN号
void setISBN(String ISBN);//设置图书ISBN号
String getName();//返回图书名称
void setName(String name);//设置图书名称
String getAuthor();//返回图书作者名称
void setAuthor(String author);//设置图书作者名称
String getPublish();//返回图书出版社名称
void setPublish(String publish);//设置图书出版社名称
String getDate();//返回图书出版日期
void setDate(String date);//设置图书出版日期
getPrice();//返回图书价格
void setPrice(double price);//设置图书价格
String getType();//返回图书类型
void setType(String type);//设置图书类型
getIson();//返回图书状态
void setIson(String ison);//设置图书状态
int compareTo(book o);//对比价格:用于对比本实例的price变量与其他实例o的price,协助ManageSystem类中的排序功能的完成
}
//ManageSystem类
public class ManageSystem {
ArrayList<book> create();//创建图书管理系统
void output(ArrayList<book> library);//输出图书信息
void search(ArrayList<book> library);//根据指定的ISBN或书名查找相应的图书信息
book insert();//插入一种新的图书信息
ArrayList<book> delete(ArrayList<book> library);//删除一种图书信息
ArrayList<book> change(ArrayList<book> library);//根据指定的ISBN,修改该图书的价格
void compare(ArrayList<book> library);//将图书按价格由低到高进行排序
int calculate(ArrayList<book> library);//统计图书表中的图书数量
void outputData(ArrayList<book> library);//将最新的图书信息存为文件导出
ArrayList<book> importData(ArrayList<book> library);//从文件中读图书信息到内存
}
4、图书存储结构描述
顺序表是线性表的顺序存储结构,是指用一组连续的存储单元依次存放线性表的数据元素。在顺序存储结构下,逻辑关系相邻的两个元素在物理位置上也相邻,这是顺序表的特点。
顺序表适宜于做查找这样的静态操作,顺序存储的优点是存储密度大,存储空间利用率高。缺点是插入或删除元素时不方便,需要移动大量元素o(n),预先分配空间需按最大空间分配,利用不充分,表容量难以扩充。
要完成这个题目,主要是建立图书信息的存储。本项目采用线性表的顺序存储结构。以图书信息为例,本项目的数据是一组图书信息,每条图书信息由图书ISBN号、图书名称、作者名称、出版社名称等信息组成,这组图书信息具有相同特性,属于同一数据对象,相邻元素之间存在序偶关系,这些数据具有线性表中数据元素的性质,所以该系统的数据采用线性表来存储。本图书管理系统分为两个结构体,一个是图书结构体,用于存放图书的基本信息,另一个是图书管理结构体,实现管理图书的功能。图书的存储结构用ArrayList实现。
具体存储操作:在ManageSystem类中获取一本书籍的具体信息,通过book类初始化方法实例化为一个book实例,然后存入ManageSystem类中的ArrayList列表中。
5、基本操作的算法描述
book.java:
// book类,用于实例化图书以及一些基本操作。public class book implements Comparable<book> {
book类中定义了私有成员变量:ISBN(书籍ISBN号),name(书名),author(作者),publish(出版社),date(出版日期),price(价格),type(类型),ison(状态)。
// 初始化方法:将一本书初始化成为一个book实例。 public book(String ISBN,String name,String author,String publish,String date,double price,String type,String ison){}
// getter和setter:每个成员变量的getter与setter方法。
public String getISBN() {}
public void setISBN(String ISBN) {}
public String getName() {}
public void setName(String name) {}
public String getAuthor() {}
public void setAuthor(String author) {}
public String getPublish() {}
public void setPublish(String publish) {}
public String getDate() {}
public void setDate(String date) {}
public double getPrice() {}
public void setPrice(double price) {}
public String getType() {}
public void setType(String type) {}
public String getIson() {}
public void setIson(String ison) {}
// 对比价格:为Book类接入Comparable<>接口,通过重写compareTo方法实现组内的排序。在实现该方法时,通过Double的compare直接对比本实例的price(getPrice())和其他实例o的price(o.getPrice()),当前者大时,返回1;当后者大时,则返回-1; public int compareTo(book o){
return Double.compare(getPrice(), o.getPrice());
}
}
ManageSystem.java:
// ManageSystem类,用于存储图书与管理图书。
public class ManageSystem {
// main方法:主要执行命令行的信息输入与输出、调用类中的方法。
public static void main(String[] args) { 1.接收命令行输入
2.调用create方法创建library顺序表
3. 创建图书管理系统的账号与密码列表
4. while循环判断登录是否成功(标志位):
a. 输出指示信息(请输入账号/密码)
b. 获得账号和密码
c. 遍历账号列表
c1:对比输入的账号是否与取出的账号相同,对比输入的密码与取出账号对应的密码是否相同
True:
c1.1:调用create方法,创建library列表
c1.2:输出提示信息(登录成功)
c1.3:修改标志位为false,跳出while循环
False:继续执行
d. 判断标志位是否仍为true
True:输出提示信息(登陆失败)
5. while循环判断是否继续执行命令(标志位):
a. 输出命令相关指示(当前图书馆里系统;1:输出信息;2:查找图书……)
b. 判断命令行输入是否为整数
False:
b1. 接收命令行输入
b2. 输出提示信息(输入有误)
True:
b1. 接收命令行输入的代号
b2. switch条件执行:
b2.1:代号为-1,修改标志位为false,结束循环;
b2.2:代号为1,调用output方法,传入library列表;
b2.3:代号为2,调用search方法,传入library列表;
b2.4:代号为3,调用insert方法实例化一个新的图书实例insert,通过ArrayList的add方法将insert加入library的末尾。
b2.5:代号为4,调用delete方法,传入library列表;
b2.6:代号为5,调用change方法,传入library列表;
b2.7:代号为6,调用compare方法,传入library列表;
b2.8:代号为7,输出提示性语句“图书馆内一共有x册图书”,在x处调用calculate方法;
b2.9:代号为8,调用outputData方法,传入library列表;
b2.10:代号为9,调用importData方法,传入一开始创建的或者旧的library列表,返回新的导入了文件信息后的列表赋值给library。
}
// 创建:登录成功后默认直接创建一个空顺序表,用来准备放置book实例
public static ArrayList<book> create(){
1. 初始化book泛型顺序表library
2. 调用printTitle方法,输出信息表表头
3. 返回library列表
}
// 输出:尽量模仿表格形式输出图书信息,分为表头与各条图书信息。
// 输出:表头一定输出,图书信息的输出取决于library中是否有图书
public static void output(ArrayList<book> library){
1. 调用printTitle方法,输出信息表表头
2. 遍历library列表
a. 调用printContent方法,输出当前的book实例的具体信息
}
// 搜索:根据ISBN号或书名进行搜索book实例。
// 搜索:由于同一图书可能存在多本库存或者同一书名有不同两本图书,因此需遍历完整个library,存在输出多条图书信息的可能性。
public static void search(ArrayList<book> library){
1. 创建命令行输入
2. 输出提示信息(想要查询的书籍的ISBN或名称)
3. 接收命令行输入的字符串
4. 初始化布尔标志位为false
5. 遍历library列表
a. 判断当前book的ISBN号或名称是否等于接收的字符串
True:
a1. 判断当前book是否为匹配的第一个book
True:
a1.1:输出提示信息
a1.2:调用printTitle方法,输出信息表表头
a1.3:修改标志位为true,表明下次匹配不再是第一次匹配
False:继续执行
a2. 调用printContent方法,输出当前的book实例的具体信息
6. 判断标志位是否仍为false
True:
a. 输出提示信息(找不到该图书)
}
// 插入:从命令行获取新的图书数据,需要按顺序输入完整的数据,用一个空格隔开。
public static book insert(){
1. 创建命令行输入
2. 调用printTitle方法,输出信息表表头
3. 输出提示信息(输入新增书籍信息)
4. 接收命令行输入
5. 将命令行输入的字符串分割成字符串列表
6. 通过字符串列表创建新的book实例
7. 输出提示信息(加入成功)
8. 返回该book实例
}
// 删除:根据ISBN号删除图书条目,限制条件为书本处于“在架上”的状态,删除前会输出被删除的图书条目。
public static ArrayList<book> delete(ArrayList<book> library) {
1. 创建命令行输入
2. 输出提示信息(删除的书籍的ISBN号)
3. 接收命令行输入
4. 初始化标志位为false
5. 遍历library列表
a. 获取当前book实例
b. 判断输入的ISBN号是否与当前book实例相同,同时判断该书在架上
True:
b1. 调用printTitle方法,输出信息表表头
b2. 调用printContent方法,输出当前的book实例的具体信息
b3. 删除library列表中的当前book实例
b4. 修改标志位为true
b5. 输出提示信息(删除成功)
b6. 结束遍历
False:
继续执行
6. 判断标志位是否为false
True:
输出提示信息(删除失败)
7. 返回最新的library列表
}
// 修改:根据ISBN号修改图书价格。
// 由于可能存在多本相同书籍,所以需要用户输入一次,系统修改多条数据。
public static ArrayList<book> change(ArrayList<book> library){
1. 创建命令行输入
2. 输出提示信息(修改的图书的ISBN号)
3. 接收命令行输入的ISBN号
4. 定义修改后的价格c,初始化为0;
5. 初始化标志位为true
6. 遍历library列表:
a. 判断输入的ISBN号是否与当前book实例的ISBN相同
a1. 判断标志位,为true表示当前是第一次匹配到该ISBN号
True:
a1.1 获取命令行输入的价格,赋值给前面定义的变量c
a1.2 修改标志位为false,表示后面匹配到的book实例都不是第一个
a2. 修改当前的book实例的价格
7. 判断标志位:
True:输出(修改成功)
False:输出(修改失败)
8. 返回最新的library列表
}
// 排序:根据图书的价格进行排序。
// 排序:为了不改变原数据的顺序,选择复制library进行临时性的排序,并输出。
public static void compare(ArrayList<book> library){
1. 初始化一个复制版library空列表
2. 遍历将library的内容加入到复制版library中
3. 依据book中的compareTo方法对复制版library进行排序
4. 调用output方法,将复制版library输出
}
// 计数:计算图书的总数,相当于计算library的大小。
public static int calculate(ArrayList<book> library){
1. 返回library的size
}
// 导出:将library内容以book数据条形式导出至book.txt文本文件内
public static void outputData(ArrayList<book> library) throws IOException {
1.获取或创建代码文件同目录下的book.txt文件
2.开启文件字节输出流,并同时清空book.txt文件内所有内容
3.遍历library的book数据条,并输出至book.txt文件内
4.关闭文件字节输出流
5.输出提示信息(成功输出)
}
// 导入:将book.txt文本文件内容以book数据条形式导入并插入当前library尾部
public static ArrayList<book> importData(ArrayList<book> library) throws IOException {
1.获取或创建代码文件同目录下的book.txt文件
2.开启文件字节输入流
3.为文件字节输入流设置字符流解码器
4.为字符流设置输入缓冲区
5.while循环读取文件整行并判断其是否为空
a. 将读取行以制表符分为割符分割存入字符串数组中
b. 将分割好的字符串数组转换成book实例
c. 将book实例尾插入library列表
6.关闭文件字节输入流
7.输出提示信息(成功导入)
8.返回最新的library列表
}
// 输出表头:尽量模仿表格形式(单元格大小相同),输出固定表头。
public static void printTitle(){
1. 定义字符串数组,将变量名称按顺序放入数组中(ISBN,名称,作者,出版社……)
2. 遍历字符串数组,printf按格式输出每一个字符串
3. 另起一行,再在下一行输出长串分隔符“---------”
}
// 输出图书信息:尽量模仿表格形式(单元格大小相同),输出传入的book实例的每个属性
public static void printContent(book b){
1. 定义字符串数组,将输入的book实例中的属性按顺序放入数组中
2. 遍历字符串数组,printf按格式输出每一个字符串
3. 另起一行,再在下一行输出长串分隔符“---------”
}
6、测试
6.1测试数据集
ISBN | name | author | publish | date | price | type | ison |
0000000001 | 大学计算机基础 | 陈建勋 | 高等教育出版社 | 2007-08-10 | 58.00 | 计算机类 | 在架上 |
0000000002 | C语言 | 王远林 | 电子工业出版社 | 2000-04-12 | 48.00 | 计算机类 | 已借阅 |
0000000003 | 组织行为学 | 刘烨 | 中国人民出版社 | 1997-09-28 | 76.00 | 管理类 | 在架上 |
0000000004 | 管理学 | 高敏 | 清华大学出版社 | 2020-05-01 | 57.00 | 管理类 | 已借阅 |
0000000005 | 统计学 | 贺天 | 北京大学出版社 | 2018-03-23 | 38.00 | 数统类 | 正在订购 |
0000000006 | 概率论 | 李毅 | 中国工业出版社 | 2004-05-16 | 39.00 | 数统类 | 在架上 |
0000000007 | 糖尿病的正确饮食 | 钟娅 | 中国轻工出版社 | 2020-10-01 | 89.00 | 医学类 | 在架上 |
0000000008 | 人体构造 | 黄远 | 河北科学出版社 | 2016-08-13 | 99.00 | 医学类 | 正在订购 |
0000000009 | 宏观经济学 | 刘叶 | 清华大学出版社 | 2015-03-10 | 67.00 | 经济类 | 正在订购 |
0000000010 | 微观经济学 | 王陆 | 中国人民出版社 | 2003-04-28 | 54.00 | 经济类 | 已借阅 |
0000000010 | 微观经济学 | 王陆 | 中国人民出版社 | 2003-04-28 | 54.00 | 经济类 | 已借阅 |
6.2测试程序运行结果截图
(1)登录和创建
(2)输出
(3)查找
(4)插入
(5)删除
(6)修改
(7)排序
(8)计数
(9)导出
(10)读入
(11)菜单
7、存在的问题与思考
(1)没有考虑完整异常情况:由于时间原因,在编写代码的时候基本只考虑了输入正确的情况,除了文件导入导出外没有考虑异常情况的处理(try-catch)。但是在代码编写过程中,尽量把可以考虑的情况考虑进去,如在执行功能选择switch语句前,判断输入是否为整数,如果不为整数就输出报错,输入为整数才获取输入,进入switch语句,尽可能保持无异常情况的发生。
(2)功能不够丰富:由于时间原因,完成了基本的要求后只增加了登录功能,其余都是在原有代码基础上进行修改,使得交互更加舒适。
(3)交互效果有待提高:由于没有时间将系统以可视化的方式展现,希望能够在命令行的演示下尽量提高交互效果。在调整交互效果的过程中除了加入很多提示信息,修改图书信息表示方式(尽量模仿表格方式)外,在适当的地方加入了空行以达到分割显示的效果。
(4)没能活用现有类对程序进行简化:我们在考虑“图书出版日期”这一属性时,曾经考虑过采用Date类进行记录,但是由于它的toString方法是转换成一个16进制的数值字符串,不方便在别的方法中进行调用,所以我们直接采用了String类进行记录。但这样不利于后期的改进,对于一些时间记录上的处理也会更麻烦。