问题描述
读取给定的图书文件book.txt中的信息(book.txt中部分图书信息如下图所示),完成一个图书信息管理系统,该系统的各个功能模块要求利用菜单选项进行选择。
系统功能要求
图书浏览
读取book.txt中的文件信息并依次输出所有图书信息(书号、书名、价格),包括文件前两行的标题说明信息。
图书统计
统计book.txt中的图书总数n并输出。
图书插入
根据指定的位置i(1≤i≤n+1)和给定的一本图书信息,将该图书插入到位置i,并将变化后的图书信息回写到book.txt。
图书删除
根据指定的位置i(1≤i≤n),删除该位置上的图书信息,并将变化后的图书信息回写到book.txt。
图书查找
① 按位置进行查找:根据输入的位置i(1≤i≤n),查找位置i上的图书信息并输出;
② 按书名进行查找:根据输入的书名,查找该图书的信息并输出(如果有多本,则全部输出)。
价格更新
将价格小于45元的图书价格提高20%,价格大于等于45元的图书价格提高10%,将修改后的图书信息重新写入新文件book-newprice.txt中。
价格排序
按图书价格升序排序,将排序后的图书信息重新写入新文件book-newsort.txt中。
逆序存储
将book.txt中的全部图书逆序存储(即最后一本置于原第一本位置)写入新文件book-newinverse.txt中。
【数据结构要求】
图书数据类型的定义需要采用数据结构教材(参考文献[1])24页中的顺序表类型定义方式,如下所示。
算法实现要求
正确性
在合理的数据输入下,能够在有限的运行时间内得到正确的结果。
可读性
程序结构清晰,易于理解,程序要求具有规范的缩进格式,关键语句添加适当的注释,变量或函数名等标识符按照见名知义的原则命名。
健壮性
当输入的数据非法时,能适当地做出正确反应或进行相应处理,而不会产生一些莫名其妙的输出结果。例如,查找不到时给出“图书不存在,查找失败”的提示,插入或删除位置非法时给出“指定位置非法”的提示等。
高效性
分析每个算法的时间复杂度和空间复杂度,并确保时间高效和空间高效。
任务选做要求
基于链式存储结构实现上述所有功能,即将图书数据类型的定义改为数据结构教材(参考文献[1])29页中的链表类型定义方式,如下所示。
具体实现时需要将上述定义中的ElemType改为如下定义的Book类型取可,即每一本图书作为链表的一个结点。
typedef struct //图书信息定义
{
char no[20]; //图书ISBN
char name[50]; //图书名字
float price; //图书价格
} Book;
参考文献
[1] 严蔚敏, 李冬梅, 吴伟民.数据结构(C语言版)(第2版)双色版.人民邮电出版社, 2021.
[2] 李冬梅, 田紫微.数据结构习题解析与实验指导(第2版).人民邮电出版社, 2022.
[3] C语言教程. https://www.runoob.com/cprogramming/c-tutorial.html.
以下是笔者在同目录下文件 book.txt 生成的随机数据,便于调试
9781334512350 程序设计艺术 89.90
9781344656791 数据库原理 95.80
9781355712402 网络安全入门 99.70
9781366856813 C++高级编程 105.60
9781377912454 深度学习研究 110.50
9781388056865 大数据分析 104.40
9781399112466 游戏开发秘籍 89.30
9781400256917 移动应用设计 97.20
9781411312478 云服务架构 108.10
9781422456929 人工智能未来 115.00
9781433512480 系统集成方法 98.90
9781444656931 前端开发进阶 88.80
9781455712492 3D图形编程 119.70
9781466856943 VR技术实践 129.60
9781477912504 物联网技术 104.50
9781488056955 编译原理简介 95.40
9781499112516 数字设计基础 86.30
9781500256967 软件工程方法 107.20
9781511312528 IT项目管理 96.10
9781522456979 企业网络解决方案 112.00
9781533512530 运算放大器设计 93.90
9781544657011 深度学习框架 92.80
9781555712562 微处理器原理 101.70
9781566857063 数据挖掘技术 109.60
9781577912594 网络编程入门 106.50
9781588057105 机器人技术 105.40
9781599112656 嵌入式系统设计 104.30
9781600257157 量子计算概论 102.20
9781611312678 分布式系统原理 103.10
9781622457109 电路设计基础 101.00
9781633512670 软件测试方法 100.90
9781644657151 无线通信技术 99.80
9781655712712 系统分析与设计 98.70
9781666857253 开源软件应用 97.60
9781677912754 高性能计算 96.50
9781688057305 网站开发实践 95.40
9781699112856 编程语言概览 94.30
9781700257357 安全编程技巧 93.20
9781711312858 计算机图形学 92.10
9781722457409 操作系统原理 91.00
9781733512950 软件架构设计 89.90
9781744657491 互联网金融 88.80
9781755712952 区块链技术 87.70
9781766857493 人工智能伦理 86.60
9781777913054 量子机器学习 85.50
9781788057505 虚拟现实技术 84.40
9781799113156 云计算安全 83.30
9781800257557 网络协议分析 82.20
9781811313058 数据中心设计 81.10
9781822457609 大数据存储 80.00
完整 c o d e code code
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <windows.h>
#include <stdlib.h>
#define cls system("cls")
#define endl puts("")
#define title(x) printf("========%s========\n", x)
#define DIR "./book.txt"
#define DIR_NewPrice "./book-newprice.txt"
#define DIR_Inverse "./book-newinverse.txt"
#define DIR_Sort "./book-newsort.txt"
typedef struct {
char no[20], name[50];
float price;
} Book;
typedef struct LNode {
Book data;
struct LNode* next;
} *LinkList;
LinkList InitList();
int Read(LinkList L, int Type); // Type = 0 头插法, Type = 1 尾插法
void Write(LinkList L, int Type); // 写入文件
// Type = 0 代表源文件
// Type = 1 代表逆序存储的文件
// Type = 2 代表存储更新的价格
// Type = 3 代表存储按价格顺序的文件
void StoreInverse(LinkList L); // 逆序存储
void Output(LinkList L, int count); // 所有图书输出到屏幕
int Add(LinkList L, int count); // 新增图书
int Erase(LinkList L, int count); // 移除图书
int SearchByID(LinkList L, int count); // 按索引搜索
int SearchByName(LinkList L, int count); // 按书名搜索
void Search(LinkList L, int count); // 搜索
void Update(LinkList L); // 更新书的价格
void Edit(LinkList L, int count); // 图书管理
void Sort(LinkList L, int count); // 按价格排序
void CannotOpenFile(); // 报错:无法打开文件
void CannotCloseFile(); // 报错:无法关闭文件
void CannotAllocateMemory(); // 报错:无法分配内存
int main(void) {
while (true) {
LinkList L = InitList();
int count = Read(L, 1);
if (count == -1) return 0;
int op;
do {
cls;
title(" 安徽工业大学图书馆计算机图书采购管理系统 ");
endl;
puts("\t\t0 > 退出系统");
puts("\t\t1 > 图书列表");
puts("\t\t2 > 图书管理");
puts("\t\t3 > 查找图书");
puts("\t\t4 > 逆序存储");
puts("\t\t5 > 价格升序");
endl;
title("==========================================");
scanf("%d", &op);
} while (op < 0 || op > 6);
switch (op) {
case 0: // 退出系统
cls;
title(" 安徽工业大学图书馆计算机图书采购管理系统 ");
endl;
puts("\t\t\t已退出系统");
endl;
title("==========================================");
return 0;
break;
case 1: // 图书列表
Output(L, count);
puts("输入任意并回车返回主界面");
int op;
scanf("%d", &op);
break;
case 2: // 图书管理
Edit(L, count);
break;
case 3: // 查找图书
Search(L, count);
break;
case 4: // 逆序存储
StoreInverse(L);
break;
case 5: // 按价格升序
Sort(L, count);
break;
}
}
return 0;
}
void CannotOpenFile() {
cls;
title(" 安徽工业大学图书馆计算机图书采购管理系统 ");
endl;
puts("\t\t无法打开文件!");
endl;
title("==========================================");
Sleep(1000);
}
void CannotCloseFile() {
cls;
title(" 安徽工业大学图书馆计算机图书采购管理系统 ");
endl;
puts("\t\t无法关闭文件!");
endl;
title("==========================================");
Sleep(1000);
}
void CannotAllocateMemory() {
cls;
title(" 安徽工业大学图书馆计算机图书采购管理系统 ");
endl;
puts("\t\t无法分配内存!");
endl;
title("==========================================");
Sleep(1000);
}
LinkList InitList() {
LinkList L = (LinkList)malloc(sizeof(LNode));
if (L == NULL) {
CannotAllocateMemory();
exit(-1);
}
L->next = NULL;
return L;
}
int Read(LinkList L, int Type) {
FILE* fpRead;
if ((fpRead = fopen(DIR, "r")) == NULL) {
CannotOpenFile();
fclose(fpRead);
exit(-1);
}
LinkList last;
if (Type == 1) last = L; // 尾插法记录末节点
int count = 0;
while (!feof(fpRead)) {
count ++;
LinkList elem = (LinkList)malloc(sizeof(LNode));
fscanf(fpRead, "%s%s%f\n", elem->data.no, elem->data.name, &elem->data.price);
if (!Type) { // 头插法
elem->next = L->next;
L->next = elem;
} else { // 尾插法
last->next = elem;
elem->next = NULL;
last = elem;
}
}
if (fclose(fpRead)) {
CannotCloseFile();
exit(-1);
}
return count;
}
void Write(LinkList L, int Type) {
FILE* fpWrite;
if (Type == 0) fpWrite = fopen(DIR, "w");
else if (Type == 1) fpWrite = fopen(DIR_Inverse, "w");
else if (Type == 2) fpWrite = fopen(DIR_NewPrice, "w");
else fpWrite = fopen(DIR_Sort, "w");
if (fpWrite == NULL) {
CannotOpenFile();
exit(-1);
}
for (LinkList elem = L->next; elem != NULL; elem = elem->next) {
float Now = elem->data.price;
if (Type == 2) {
if (Now < 45) Now *= 1.2;
else Now *= 1.1;
}
fprintf(fpWrite, "%s %s %.2f\n", elem->data.no, elem->data.name, Now);
}
if (fclose(fpWrite)) {
CannotCloseFile();
exit(-1);
}
}
void StoreInverse(LinkList L) {
LinkList L2 = (LinkList)malloc(sizeof(LNode));
L2->next = NULL;
Read(L2, 0);
Write(L2, 1);
cls;
title(" 安徽工业大学图书馆计算机图书采购管理系统 ");
endl;
puts("\t\t已完成逆序存储");
endl;
title("==========================================");
Sleep(1000);
}
void Output(LinkList L, int count) {
cls;
title(" 安徽工业大学图书馆计算机图书采购管理系统 ");
endl;
printf("一共索引到 %d 条图书记录\n", count);
endl;
puts("索引 \tISBN\t\t书名\t\t定价");
int cnt = 1;
for (LinkList elem = L->next; elem != NULL; elem = elem->next, cnt ++) {
printf("%2d %s %-18s %5.2lf\n", cnt, elem->data.no, elem->data.name, elem->data.price);
}
endl;
printf("一共索引到 %d 条图书记录\n", count);
endl;
title("==========================================");
}
int Add(LinkList L, int count) {
int pos;
do {
Output(L, count);
printf("请输入数字 1 ~ %d,作为插入的位置:", count + 1);
scanf("%d", &pos);
} while (pos < 1 || pos > count + 1);
LinkList tmp = (LinkList)malloc(sizeof(LNode));
printf("ISBN:");
scanf("%s", tmp->data.no);
printf("书名:");
scanf("%s", tmp->data.name);
printf("定价:");
scanf("%f", &tmp->data.price);
int cnt = 1;
for (LinkList elem = L; elem != NULL; elem = elem->next, cnt ++) {
if (cnt == pos) {
tmp->next = elem->next;
elem->next = tmp;
break;
}
}
Write(L, 0);
return count + 1;
}
int Erase(LinkList L, int count) {
int pos;
do {
cls;
Output(L, count);
endl;
printf("请输入数字 1 ~ %d,作为删除的位置:", count);
scanf("%d", &pos);
} while (pos < 1 || pos > count);
int cnt = 1;
for (LinkList elem = L->next; elem != NULL; elem = elem->next, cnt ++) {
if (cnt == pos) {
char c[20];
do {
cls;
title(" 安徽工业大学图书馆计算机图书采购管理系统 ");
endl;
puts("索引 \tISBN\t\t书名\t\t定价");
printf("%2d %s %-18s %5.2lf\n", cnt, elem->data.no, elem->data.name, elem->data.price);
title("==========================================");
endl;
printf("是否确定删除索引第 %d 本书?(Y/N):", pos);
scanf("%s", c);
} while (c[0] != 'Y' && c[0] != 'N');
if (c[0] == 'N') return count;
elem->next = elem->next->next;
break;
}
}
Write(L, 0);
return count - 1;
}
int SearchByID(LinkList L, int count) {
int pos;
do {
cls;
title(" 安徽工业大学图书馆计算机图书采购管理系统 ");
endl;
printf("请输入数字 1 ~ %d,作为查找的位置:", count);
scanf("%d", &pos);
} while (pos < 1 || pos > count);
return pos;
}
int SearchByName(LinkList L, int count) {
char Name[60];
int cnt;
while (true) {
cls;
title(" 安徽工业大学图书馆计算机图书采购管理系统 ");
endl;
printf("请输入书名以查找:");
scanf("%s", Name);
cnt = 1;
for (LinkList elem = L->next; elem != NULL; elem = elem->next, cnt ++) {
if (!strcmp(elem->data.name, Name)) return cnt;
}
if (Name[0] == 'q') return -1;
if (cnt == count + 1) {
cls;
title(" 安徽工业大学图书馆计算机图书采购管理系统 ");
endl;
puts("\t\t未查找到相关书名");
endl;
title("==========================================");
Sleep(1000);
break;
}
}
return -1;
}
void Search(LinkList L, int count) {
int op;
do {
cls;
title(" 查找图书 ");
endl;
puts("\t0 > 返回");
puts("\t1 > 按索引查找");
puts("\t2 > 按书名查找");
endl;
title("==========");
scanf("%d", &op);
} while (op < 0 || op > 2);
int pos;
switch (op) {
case 0:
return;
break;
case 1:
pos = SearchByID(L, count);
break;
case 2:
pos = SearchByName(L, count);
break;
}
if (pos == -1) return;
int cnt = 1;
for (LinkList elem = L->next; elem != NULL; elem = elem->next, cnt ++) {
if (cnt == pos) {
cls;
title(" 安徽工业大学图书馆计算机图书采购管理系统 ");
endl;
puts("找到了以下书满足搜索条件:");
endl;
puts("索引 \tISBN\t\t书名\t\t定价");
printf("%2d %s %-18s %5.2lf\n", cnt, elem->data.no, elem->data.name, elem->data.price);
endl;
title("==========================================");
endl;
puts("输入任意并回车返回主界面");
int op;
scanf("%d", &op);
return;
}
}
}
void Update(LinkList L) {
Write(L, 2);
cls;
title(" 安徽工业大学图书馆计算机图书采购管理系统 ");
endl;
puts("\t\t已完成价格更新");
endl;
title("==========================================");
Sleep(1000);
}
void Edit(LinkList L, int count) {
int op;
do {
cls;
title(" 图书管理 ");
endl;
puts("\t0 > 返回");
puts("\t1 > 新增图书");
puts("\t2 > 删除图书");
puts("\t3 > 更新价格");
endl;
title("==========");
scanf("%d", &op);
} while (op < 0 || op > 3);
switch (op) {
case 0:
return;
break;
case 1:
count = Add(L, count);
break;
case 2:
count = Erase(L, count);
break;
case 3:
Update(L);
break;
}
}
void Swap(LinkList A, LinkList B) { // 交换数据
Book C;
C = B->data;
B->data = A->data;
A->data = C;
}
void Sort(LinkList L, int count) {
LinkList L3 = (LinkList)malloc(sizeof(LNode));
L3->next = NULL;
LinkList last = L3;
for (LinkList elem = L->next; elem != NULL; elem = elem->next) {
LinkList New = (LinkList)malloc(sizeof(LNode));
New->data = elem->data;
last->next = New;
New->next = NULL;
last = New;
}
for (LinkList i = L3->next; i->next != NULL; i = i->next) // 冒泡排序
for (LinkList j = i->next; j != NULL; j = j->next)
if (i->data.price > j->data.price) Swap(i, j);
Write(L3, 3);
cls;
title(" 安徽工业大学图书馆计算机图书采购管理系统 ");
endl;
puts("\t\t已完成按价格升序");
endl;
title("==========================================");
Sleep(1000);
}