任务需求
读取给定的图书文件book.txt中的信息,完成一个图书信息管理系统,该系统的各个功能模块利用菜单选项进行选择,要求程序具有正确性、可读性(变量函数命名规范、核心语句添加注释)、健壮性(数据非法时能够进行相应处理)。
输出:读取book.txt中的文件信息并依次输出所有图书信息(书号、书名、价格)。
插入:根据指定的位置i(1≤i≤n+1)和给定的一本图书信息,将该图书插入到位置i,并将变化后的图书信息回写到book.txt。
删除:根据指定的位置i(1≤i≤n),删除该位置上的图书信息,并将变化后的图书信息回写到book.txt。
查找
1、按位置进行查找:根据输入的位置i(1≤i≤n),查找位置i上的图书信息并输出;
2、按书名进行查找:根据输入的书名,查找该图书的信息并输出(如果有多本,则全部输出)。
修改:将价格小于25元的图书价格提高20%,价格大于等于25元的图书价格提高10%,将修改后的图书信息写入文件book_newprice.txt中。
排序:按书的价格由低到高排序写入文件book_newsort.txt中。(必须包含冒泡排序,其他排序任选)
注意:book.txt的内容如下图所示

代码
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
const int MAXSIZE = 1e5+7; //最多数据元素个数
const int MAXLEN = 107; //字符串类型数据的最长长度
const int inf = 0x3f3f3f3f; //最大的int
typedef struct{
char no[MAXLEN]; //图书编号
char name[MAXLEN]; //图书名字
double price; //图书价格
}Book;
typedef struct LNode{
Book data; //结点的数据域
int length; //节点的数据域(计算头结点L的长度)
struct LNode *next; //结点的指针域
}LNode, *LinkList;
void Init(LinkList &L); //初始化
void Destroy(LinkList &L); //释放
void ReadFromFile(LinkList &L); //读文件
void WriteIntoFile(LinkList &L, const char *file); //写文件
void IllegalInput(string menu); //非法输入
void ShowMainMenu(); //显示主菜单
void ShowAll(LinkList &L); //显示所有图书信息
void Insert(LinkList &L); //插入图书信息
void Erase(LinkList &L); //删除图书信息
void Modify(LinkList &L); //修改图书信息
void Quit(); //退出
void ShowSearchMenu(); //显示查找菜单
void SearchByPosition(LinkList &L); //通过位置查找图书信息
void SearchByName(LinkList &L); //通过书名查找图书信息
void ShowSortMenu(); //显示查找菜单
void InsertionSort(LinkList &L); //插入排序
void SelectionSort(LinkList &L); //选择排序
void BubbleSort(LinkList &L); //冒泡排序
void QuickSort(LinkList &L); //快速排序
void MergeSort(LinkList &L); //归并排序
int main(){
ShowMainMenu();
return 0;
}
//主菜单界面
void ShowMainMenu(){
system("cls"); //清屏
printf("*************************图书管理系统*************************\n");
printf("显示所有图书信息---------------------------------------------1\n");
printf("插入---------------------------------------------------------2\n");
printf("删除---------------------------------------------------------3\n");
printf("查找---------------------------------------------------------4\n");
printf("修改---------------------------------------------------------5\n");
printf("排序---------------------------------------------------------6\n");
printf("退出---------------------------------------------------------7\n\n");
printf("请输入想进入的二级菜单:");
LinkList L;
Init(L);
ReadFromFile(L);
int op;
scanf("%d", &op);
switch(op){
case 1:{ //输入1,显示所有书本
ShowAll(L);
break;
}
case 2:{ //输入2,插入功能
Insert(L);
break;
}
case 3:{ //输入3,删除功能
Erase(L);
break;
}
case 4:{ //输入4,显示搜索界面
ShowSearchMenu();
break;
}
case 5:{ //输入5,修改
Modify(L);
break;
}
case 6:{ //输入6,显示排序界面
ShowSortMenu();
break;
}
case 7:{ //输入7,退出程序
Quit();
break;
}
default:{ //非法输入
IllegalInput("main");
break;
}
}
Destroy(L); //释放空间
}
//查找界面
void ShowSearchMenu(){
system("cls"); //清屏
printf("************************请选择查找方式************************\n");
printf("按位置查找---------------------------------------------------1\n");
printf("按书名查找---------------------------------------------------2\n");
printf("返回一级菜单-------------------------------------------------3\n\n");
printf("请输入您所选的排序方式:");
LinkList L;
Init(L);
ReadFromFile(L);
int op;
scanf("%d", &op);
switch(op){
case 1:{ //输入1,根据位置查找
SearchByPosition(L);
break;
}
case 2:{ //输入2,根据名字查找
SearchByName(L);
break;
}
case 3:{ //输入3,返回主菜单
ShowMainMenu();
break;
}
default:{ //非法输入
IllegalInput("search");
break;
}
}
Destroy(L); //释放空间
}
//排序界面
void ShowSortMenu(){
system("cls"); //清屏
printf("************************请选择排序方式************************\n");
printf("插入排序-----------------------------------------------------1\n");
printf("选择排序-----------------------------------------------------2\n");
printf("冒泡排序-----------------------------------------------------3\n");
printf("快速排序-----------------------------------------------------4\n");
printf("归并排序-----------------------------------------------------5\n");
printf("返回一级菜单-------------------------------------------------6\n\n");
printf("请输入您所选的排序方式:");
LinkList L;
Init(L);
ReadFromFile(L);
int op;
scanf("%d", &op);
switch(op){
case 1:{ //输入1,执行插入排序
InsertionSort(L);
break;
}
case 2:{ //输入2,执行选择排序
SelectionSort(L);
break;
}
case 3:{ //输入3,执行冒泡排序
BubbleSort(L);
break;
}
case 4:{ //输入4,执行快速排序
QuickSort(L);
break;
}
case 5:{ //输入5,执行归并排序
MergeSort(L);
break;
}
case 6:{ //输入6,返回主菜单
ShowMainMenu();
break;
}
default:{ //非法输入
IllegalInput("sort");
break;
}
}
Destroy(L); //释放空间
}
//初始化
void Init(LinkList &L){
L = new LNode; //生成一个新结点作为头结点,用头指针L指向头结点
L->next = NULL; //头指针指向NULL
L->length = 0; //长度为0
}
//递归释放整个链表
void Destroy(LinkList &L){
if (L != NULL){
Destroy(L->next);
delete L;
}
}
//读文件
void ReadFromFile(LinkList &L){
ifstream rd("book.txt"); //新建一个文件输出流指针,打开文件book.txt
if (! rd){
exit(0); //如果打开失败,异常结束
}
char title[MAXLEN];
char noTitle[MAXLEN], nameTitle[MAXLEN], priceTitle[MAXLEN];
rd >> title; //读取标题
rd >> noTitle >> nameTitle >> priceTitle; //读取标题
LinkList p = L; //使尾指针p位于表头
Book book;
while (rd >> book.no >> book.name >> book.price){
//后插法创建单链表
LinkList q = new LNode; //生成一个新结点q,使得p结点之后为q结点
q->data = book; //q的数据域为该书的信息
q->next = NULL; //q的指针指向NULL
p->next = q; //p的指针指向q
p = q; //将q的信息传给p,使p又重新变为指向新的尾指针
L->length++; //链表的长度加1
}
rd.close(); //关闭文件流指针
}
//写文件
void WriteIntoFile(LinkList &L, const char *file){
ofstream w(file); //新建一个文件输入流指针,打开文件file
if (! w){
exit(0); //如果打开失败,异常结束
}
w << "北京林业大学图书馆计算机类图书采购列表" << endl;
w << "ISBN 书名 定价" << endl;
LinkList p = L; //使尾指针p位于表头
while (p->next){ //p的下一个不为空
w << p->next->data.no << " " << p->next->data.name << " " << p->next->data.price << endl; //将p的下一个的图书信息输出到文件流中
p = p->next; //p指向下一个
}
w.close(); //关闭文件流指针
}
//非法输入
void IllegalInput(string menu){
printf("输入失败,请重新输入!");
system("pause"); //需要输入一个字符程序才能执行
getchar(); //读取字符
//根据menu分别进入不同的菜单
if (menu == "main"){
ShowMainMenu();
}else if (menu == "search"){
ShowSearchMenu();
}else if (menu == "sort"){
ShowSortMenu();
}
}
//显示所有图书信息
void ShowAll(LinkList &L){
system("cls"); //清屏
if (L->length == 0){ //表长为0,没有图书
printf("暂无图书!");
}else{
printf("所有的图书信息:\n\n");
printf(" ISBN 书名 定价\n");
printf("=================================================================\n");
LinkList p = L; //使p位于表头
while (p->next){ //p的下一个不为空
printf("%-20s%-40s%.2f\n", p->next->data.no, p->next->data.name, p->next->data.price); //将p下一个结点的图书信息输出到文件流中
p = p->next; //p的指针指向下一个结点
}
printf("=================================================================\n\n");
}
//按任意键返回主菜单
system("pause");
ShowMainMenu();
}
//插入图书信息
void Insert(LinkList &L){
system("cls"); //清屏
int pos;
Book book;
int length = 0;
printf("请输入要插入的位置(1~%d):", L->length+1);
scanf("%d", &pos);
//若想要插入的位置不在区间[1,L->length+1],则插入的位置不合法,需要重新输入位置
while (pos < 1 || pos > L->length+1){
printf("输入不正确,请重新输入:");
scanf("%d", &pos);
}
printf("请输入图书编号:");
scanf("%s", book.no);
printf("请输入图书书名:");
scanf("%s", book.name);
printf("请输入图书价格:");
scanf("%lf", &book.price);
LinkList p = L;
int len = 0;
while (len < pos-1){
p = p->next; //查找pos-1的结点,使p指向该结点
len++;
}
LinkList q = new LNode; //生成新结点q
q->data = book; //q的数据域为该书的信息
q->next = p->next; //q的指针指向p的下一个结点
p->next = q; //p的指针指向q
L->length++; //表长加1
WriteIntoFile(L, "book.txt");; //将插入后的所有图书信息重新写入到book.txt中
printf("\n\n插入成功!\n");
//按任意键返回主菜单
system("pause");
ShowMainMenu();
}
//删除图书信息
void Erase(LinkList &L){
system("cls");
int pos;
Book book;
printf("请输入要删除的位置(1~%d):", L->length);
scanf("%d", &pos);
//若想要删除的位置不在区间[1,L->length],则删除的位置不合法,需要重新输入位置
while (pos < 1 || pos > L->length){
printf("输入不正确,请重新输入:");
scanf("%d", &pos);
}
LinkList p = L; //处于表头
int len = 0;
while (len < pos-1){
p = p->next; //查找pos-1的结点,使p为该结点
len++;
}
LinkList q = p->next; //临时保存被删除结点的地址以备释放
p->next = q->next; //使pos-1的结点p的指针指向q结点
L->length--; //表长减1
delete q; //释放pos结点的空间
WriteIntoFile(L, "book.txt");
printf("\n\n删除成功!\n");
//按任意键返回主菜单
system("pause");
ShowMainMenu();
}
//修改图书信息
void Modify(LinkList &L){
system("cls"); //清屏
LinkList p = L; //
//依次遍历所有图书,按要求提高价格
while (p->next){
if (p->next->data.price < 25){
p->next->data.price *= 1.2;
}else{
p->next->data.price *= 1.1;
}
p = p->next;
}
printf("修改后所有的图书信息:\n\n");
printf(" ISBN 书名 定价\n");
printf("=================================================================\n");
p = L->next;
while (p){
printf("%-20s%-40s%.2f\n", p->data.no, p->data.name, p->data.price);
p = p->next;
}
printf("=================================================================\n");
printf("因某些不可抗力,图书价格小于25元的书价格提高20%,图书价格大于等于25元的书价格提高10%。敬请谅解!\n\n");
WriteIntoFile(L, "book.txt"); //将修改后的所有图书信息重新写入到book.txt中
WriteIntoFile(L, "book_newprice.txt"); //将修改后的所有图书信息写入到book_newprice.txt中
//按任意键返回主菜单
system("pause");
ShowMainMenu();
}
//退出
void Quit(){
system("cls"); //清屏
printf("确定要退出?y/n:");
char op;
scanf("%c", &op);
if (op == 'n' || op == 'N'){
ShowMainMenu();
}else if (op != 'y' && op != 'Y'){
Quit();
}
}
//下面为各种查找
//按位置查找图书信息
void SearchByPosition(LinkList &L){
system("cls"); //清屏
int pos;
printf("请输入要查找的图书位置(1~%d):", L->length);
scanf("%d", &pos);
//若想要查找的位置不在区间[1,L->length],则查找的位置不合法,需要重新输入位置
while (pos < 1 || pos > L->length){
printf("输入不正确,请重新输入:");
scanf("%d", &pos);
}
LinkList p = L;
for (int i = 0; i < pos; i++){
p = p->next; //查找pos-1的结点,使p位于该结点
}
printf("\n\n位于%d位的图书信息:\n\n", pos);
printf(" ISBN 书名 定价\n");
printf("=================================================================\n");
printf("%-20s%-40s%.2f\n", p->data.no, p->data.name, p->data.price);
printf("=================================================================\n\n");
//按任意键返回主菜单
system("pause");
ShowSearchMenu();
}
//按书名查找图书信息
void SearchByName(LinkList &L){
system("cls"); //清屏
char name[MAXLEN];
printf("请输入想要查找的书名:");
scanf("%s", name);
LinkList tmpList; //建立一个新的链表,用于存储书名为所找书名的图书信息
Init(tmpList);
LinkList tmpNode = tmpList; //
LinkList p = L->next;
while (p->next){ //依次遍历所有图书
if (strcmp(p->data.name, name) == 0){ //找到书名为name的图书
//将这本书的信息放入tmpList中
LinkList q = new LNode; //新建一个结点q
q->data = p->data; //q的数据域存放当前图书的数据
q->next = NULL; //q的指针指向空
tmpNode->next = q; //tmpNode的指针指向q
tmpNode = q; //将q的信息传给tmpNode,使tmpNode又重新变为指向新的尾指针
tmpList->length++; //tmpList长度加1
delete q; //释放q的空间
}
p = p->next;
}
if (tmpList->length == 0){ //找不到书名为name的书,tmpList的表长为0
printf("\n\n对不起,查无此书!\n");
}else{
printf("\n\n所有书名为%s图书信息:\n\n", name);
printf(" ISBN 书名 定价\n");
printf("=================================================================\n");
tmpNode = tmpList;
while (tmpNode->next){
printf("%-20s%-40s%.2f\n", tmpNode->next->data.no, tmpNode->next->data.name, tmpNode->next->data.price);
tmpNode = tmpNode->next;
}
printf("=================================================================\n\n");
}
Destroy(tmpList); //释放空间
//按任意键返回主菜单
system("pause");
ShowSearchMenu();
}
//下面的为各种排序
//插排
//O(N*N),稳定
void InsertionSort(LinkList &L){
system("cls");
//插入排序实现过程:
LinkList p = L;
LinkList q = new LNode; //空表,把L开头的链表一个个的插入到q开头的链表里
while (p){
LinkList tmp = q; //tmp存储新链表
LinkList tmpNext = p->next; //tmpNext为p的下一个结点
while (tmp->next && tmp->next->data.price < p->data.price){ //当tmp下一个结点图书的价格 < p结点的图书的价格
tmp = tmp->next; //tmp后移
}
p->next = tmp->next; //p的下一个结点就是tmp的下一个结点
tmp->next = p; // tmp的下个就变成了p
p = tmpNext; //p就为该节点
}
p = q->next; //p为q的下一个结点的结点
delete q; //释放空间
printf("经过插入排序后,所有的图书信息:\n\n");
printf(" ISBN 书名 定价\n");
printf("=================================================================\n");
while (p->next){
printf("%-20s%-40s%.2f\n", p->next->data.no, p->next->data.name, p->next->data.price);
p = p->next;
}
printf("=================================================================\n\n");
WriteIntoFile(L, "book_newsort.txt"); //将修改后的所有图书信息写入到book_newsort.txt中
//按任意键返回排序菜单页面
system("pause");
ShowSortMenu();
}
//选择排序
//O(N*N),不稳定
void SelectionSort(LinkList &L){
system("cls");
LinkList p = L;
while (p){
LinkList q = p->next;
LinkList key = p; //key为这趟排序价格最小的图书的结点
while (q){
if (key->data.price > q->data.price){ //如果价格比key图书的价格还小
key = q; //key指向这趟排序价格最小的图书
}
q = q->next;
}
swap(key->data, p->data); //交换key结点图书和p结点图书
p = p->next;
}
printf("经过选择排序后,所有的图书信息:\n\n");
printf(" ISBN 书名 定价\n");
printf("=================================================================\n");
p = L;
while (p->next){
printf("%-20s%-40s%.2f\n", p->next->data.no, p->next->data.name, p->next->data.price);
p = p->next;
}
printf("=================================================================\n\n");
WriteIntoFile(L, "book_newsort.txt"); //将修改后的所有图书信息写入到book_newsort.txt中
//按任意键返回排序菜单页面
system("pause");
ShowSortMenu();
}
//冒泡
//O(N*N),稳定
void BubbleSort(LinkList &L){
system("cls"); //清屏
//冒泡排序实现过程:
for (int i = 0; i < L->length-1; i++){ //执行L.length-1遍,每遍将无序中的最大的那个沉底
LinkList p = L->next; //p位于指向第一个有内容的结点
for (int j = 0; j < L->length-i-1; j++){ //因为后面i个都已经有序,只需排前面L.length-i-1个
if (p->data.price > p->next->data.price){ //若j图书的价格 > j+1图书的价格
swap(p->data, p->next->data); //j和j+1的图书交换
}
p = p->next; //p的指针指向下一个结点
}
}
printf("经过冒泡排序后,所有的图书信息:\n\n");
printf(" ISBN 书名 定价\n");
printf("=================================================================\n");
LinkList p = L;
while (p->next){
printf("%-20s%-40s%.2f\n", p->next->data.no, p->next->data.name, p->next->data.price);
p = p->next;
}
printf("=================================================================\n\n");
WriteIntoFile(L, "book_newsort.txt"); //将修改后的所有图书信息写入到book_newsort.txt中
//按任意键返回排序菜单页面
system("pause");
ShowSortMenu();
}
//快排
//O(N*log N),不稳定
void QSort(LinkList left, LinkList right){ //对区间[left,right]的快速排序
if (left == right || left->next == right){
return ; //左边位置 >= 右边位置,返回
}
int idx = left->data.price; //哨兵
LinkList mid = left, cur = left->next;
while (cur != right){
//把比哨兵小的左移,比哨兵大的右移
if (cur->data.price < idx){
mid = mid->next;
swap(cur->data, mid->data);
}
cur = cur->next;
}
swap(left->data, mid->data);
QSort(left, mid); //对左半边再次快速排序
QSort(mid->next, right); //对右半边再次快速排序
}
void QuickSort(LinkList &L){
system("cls");
QSort(L, NULL); //对区间[L,NULL]进行快速排序
printf("经过快速排序后,所有的图书信息:\n\n");
printf(" ISBN 书名 定价\n");
printf("=================================================================\n");
LinkList p = L;
while (p->next){
printf("%-20s%-40s%.2f\n", p->next->data.no, p->next->data.name, p->next->data.price);
p = p->next;
}
printf("=================================================================\n\n");
WriteIntoFile(L, "book_newsort.txt"); //将修改后的所有图书信息写入到book_newsort.txt中
//按任意键返回排序菜单页面
system("pause");
ShowSortMenu();
}
//归并排序
//O(N*log N),不稳定
LinkList Merge(LinkList l1, LinkList l2){ //合并l1和l2
if (! l1){
return l2; //若l1为空,返回l2
}
if (! l2){
return l1; //若l2为空,返回l1
}
//若都不为空
if (l1->data.price < l2->data.price){
l1->next = Merge(l1->next, l2); //若l1图书的价格 < l2图书的价格,递归排l1下一个
return l1;
}else{
l2->next = Merge(l1, l2->next); //若l2图书的价格 < l1图书的价格,递归排l2下一个
return l2;
}
}
LinkList MSort(LinkList &L){
if (! L || ! (L->next)){
return L; //当L为空或L中只有一个值时,返回
}
LinkList pre = L, low = L, fast = L; //pre:前,low:最低位,fast:最高位
while (fast && fast->next){ //当前和下一个不为空
pre = low;
low = low->next;
fast = fast->next->next; //前进2格
}
pre->next = NULL;
return Merge(MSort(L), MSort(low));
}
void MergeSort(LinkList &L){
system("cls");
LinkList p = MSort(L); //使p位于排序完的L的头结点
printf("经过归并排序后,所有的图书信息:\n\n");
printf(" ISBN 书名 定价\n");
printf("=================================================================\n");
while (p->next){
printf("%-20s%-40s%.2f\n", p->next->data.no, p->next->data.name, p->next->data.price);
p = p->next;
}
printf("=================================================================\n\n");
WriteIntoFile(L, "book_newsort.txt"); //将修改后的所有图书信息写入到book_newsort.txt中
//按任意键返回排序菜单页面
system("pause");
ShowSortMenu();
}
&spm=1001.2101.3001.5002&articleId=120412326&d=1&t=3&u=fd33e076220347f790105360d14df37d)
2378

被折叠的 条评论
为什么被折叠?



