图书信息管理系统(链表)

图书信息管理系统(链表)

任务需求

       读取给定的图书文件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();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chosen_One_13

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值