【线性表】--------图书管理系统的单链表实现

引言:学习完链表,让我们实践一下吧,废话不多说直接上代码

#define _CRT_SECURE_NO_WARNINGS//VS软件的内扩增问题
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//1.数据结构 与 结构操作设计:
    //3.1: 书籍结构的数据域------>以结构体存储 图书信息
	//      书籍结构的结构定义----->以链表存储 数据域中的东西
	//3.2: 书籍结构的操作设计------->链表基本操作:增、删、查、改



//3.1书籍结构的数据域:
struct bookinfo
{
	char name[20];  //书名 
	double price;  //价格
	int num;	  //数量
};

//书籍结构的结构定义
typedef struct book
{
	struct bookinfo data;//数据域类型为  struct bookinfo 类型,包含图书信息
	struct book* next;
} book, * Lbook;



//3.2书籍结构的操作设计
//3.2.1创建表头结点,返回头结点所在地址:
Lbook CreateHead()
{
	//动态内存申请
	Lbook headNode = (Lbook)malloc(sizeof(book));
	
	//防止对空内存操作
	if (!headNode)
	{
		printf("内存申请失败!");
		exit(-1);
	}

	//初始化
	headNode->next = NULL;
	return headNode;
}



//3.2.2创建一般结点,为插入做准备
//传入用户输入的 书籍结构的相关数据
book * Createnode(struct bookinfo data)
{
	//动态内存申请
	book * newNode = (book *)malloc(sizeof(book));

	//防止对空内存操作
	if (!newNode)
	{
		printf("内存申请失败!");
		exit(-1);
	}

	//初始化
	newNode->data = data;
	newNode->next = NULL;

	return newNode;
}


//3.2.3将创建好的一般结点 插入到存储所有数据的链表中(尾插法)
void InsertNode(Lbook headNode, struct bookinfo data)
{

	//创建结点
	book* newnode = Createnode(data);

	//创建尾指针,寻找尾结点
	book * tail = headNode;

	while (tail->next != NULL)
	{
		tail = tail->next;
	}

	//循环完毕,尾指针指向当前尾结点
	//尾插法插入新结点
	newnode->next =NULL;
	tail->next = newnode;
	tail = newnode;//不要忘记更新尾指针
}



//3.2.4按值删除
//通过书籍姓名进行按值删除操作
void DeleteNodebyname(Lbook headNode, char * bookname)
{
	//p:待删除结点前一个结点
	//q:待删除结点
	Lbook p, q;

	p = headNode;
	q=headNode->next;
	
	//由于书籍名为字符串,故需要字符串比较函数
	while(q!=NULL&&strcmp(q->data.name,bookname))
	{
		p=q;
		q = q->next;
	}


	if (!q)
	{
		printf("没有找到待删除结点!");
		return;
	}

	//删除:
	p->next = q->next;
	free(q);
	q = NULL;//注意置空
	printf("删除成功!\n");
}

//3.2.5按值查找并返回其在链表中的地址:
//通过书籍姓名进行按值查找操作
book* searchByName(Lbook headNode, char* bookname)
{
	book* p;//用来查找与传入书名相同的结点
	p = headNode->next;//首元结点
	while (p != NULL && strcmp(p->data.name,bookname))
	{
		p = p->next;
	}

	return p;//若返回NULL表示没有找到,否则找到了对应结点
}


//3.2.6打印链表中所有的图书信息
void PrintList(Lbook headNode)
{
	//从头结点开始遍历
	Lbook p = headNode->next;
	
	printf("书名\t\t价格\t\t数量\n");

	while (p)
	{
		printf("%s\t\t%.2lf\t\t%d\n", p->data.name,p->data.price,p->data.num);
		p = p->next;
	}
	printf("\n");
}


Lbook list = NULL;//定义全局的链表,用来存储所有书籍信息


//排序函数(用冒泡排序思想,升序排序)
//按图书价格排序
void bubbleSortList(book* headNode)
{
	for (book* p = headNode->next; p != NULL; p = p->next)//控制循环次数
	{
		for (book* q = headNode->next; q->next != NULL; q = q->next)//每次循环将最大的数放到最后
		{
			if (q->data.price > q->next->data.price)
			{
				//利用中间结构变量来交换两本书籍的数据顺序
				struct bookinfo tempData = q->data;
				q->data = q->next->data;
				q->next->data = tempData;
			}
		}
	}
	PrintList(list);//调用打印函数
}








//简单的直接文件操作
//所有的文件操作都直接作用于list这个全局链表(因为所有的数据都存储在list这个容器中)

//文件存写操作
void SaveInfoToFile(const char* filename, book* headNode)
{
	FILE* fp = fopen(filename, "w");//打开文件

	book* q = headNode->next;//定义临时指针q用来遍历传入链表的所有元素


	//通过q将最新数据写入文件
	while (q != NULL)
	{
		fprintf(fp, "%s\t\t%.2lf\t\t%d\n", q->data.name, q->data.price, q->data.num);
		q = q->next;
	}

	fclose(fp);//关闭文件
}


//文件读入操作
void ReadInfoFromFile(const char* filename, book* headNode)
{
	FILE* fp = fopen(filename, "r");//第一次打开文件肯定不存在


	//故当文件不存在时就创建出这个文件
	if (fp == NULL)
	{
		fp = fopen(filename, "w+");
	}

	struct bookinfo tempData;//单纯创建一个临时的数据结点(不是链表结点)

	while (fscanf(fp, "%s\t%lf\t%d\n", tempData.name, &tempData.price, &tempData.num) != EOF)
	{
		InsertNode(list, tempData);//将每次读入的数据插入到链表尾
	}

	fclose(fp);//关闭文件
}

//1.界面菜单
void makeMenu()
{
	printf("-----------------------------------------\n");
	printf("          xxoo图书馆管理系统xxoo\n");
	printf("\t\t0.退出系统\n");
	printf("\t\t1.登记书籍\n");
	printf("\t\t2.浏览书籍\n");
	printf("\t\t3.借阅书籍\n");
	printf("\t\t4.归还书籍\n");
	printf("\t\t5.书籍排序\n");
	printf("\t\t6.删除书籍\n");
	printf("\t\t7.查找书籍\n");
	printf("-----------------------------------------\n");
	printf("请输入(0~7):\n");
}






//2.交互函数
void KeyDown()
{
	int userkey = 0;

	struct bookinfo tempbook;//产生一个临时变量,存储书籍信息
	book* result = NULL;//产生一个临时容器(链表)指针,用来存储查找功能的结果
	scanf_s("%d", &userkey);
	switch (userkey)
	{
	case 0:
		printf("【退出】\n");
		printf("退出成功\n");
		system("pause");//暂停批处理文件的处理并显示消息
		exit(0);//正常关闭整个程序
		break;
	case 1:
		printf("【登记】\n");
		printf("请输入书籍信息(name,price,num):\n");
		scanf("%s %lf %d", tempbook.name, &tempbook.price, &tempbook.num);
		InsertNode(list, tempbook);

		SaveInfoToFile("bookinfo.txt", list);//每当输入了新的文件信息,就将更新后的链表存入文件中
		break;
	case 2:
		printf("【浏览】\n");
		PrintList(list);
		break;
	case 3:
		printf("【借阅】\n"); //书籍存在,可以借阅,同时数量减一;书籍不存在,借阅失败
		printf("请输入借阅的书籍名称:\n");
		scanf("%s", tempbook.name);
		result = searchByName(list, tempbook.name);
		if (result != NULL)
		{
			if (result->data.num > 0)
			{
				result->data.num--;
				printf("借阅成功!\n");
			}
			else
			{
				printf("当前书籍库存不足,请稍后几日再借阅!\n");
			}
			
		}
		else
		{
			printf("没有这本书,无法借阅!\n");
		}
		break;
	case 4:
		printf("【归还】\n");//对应书籍数量加一
		printf("请输入要归还的书籍名称:\n");
		scanf("%s", tempbook.name);
		result = searchByName(list, tempbook.name);
		if (result != NULL)
		{
			result->data.num++;
			printf("书籍归还成功!\n");
		}
		else
		{
			printf("没有这本书,请移步对应图书馆!\n");
		}
		break;
	case 5:
		printf("【排序】\n");
		bubbleSortList(list);
		break;
	case 6:
		printf("【删除】\n");
		printf("请输入删除书籍的名字:\n");
		scanf("%s", tempbook.name);
		DeleteNodebyname(list, tempbook.name);//删除对应书籍后需要同步到文件(因为此时容器中的数据并未更新到文件)
		SaveInfoToFile("bookinfo.txt", list);
		break;
	case 7:
		printf("【查找】\n");
		printf("请输入要查询的书名:\n");
		scanf("%s", tempbook.name);
		result = searchByName(list,tempbook.name);
		if (result != NULL)
		{
			printf("书名\t价格\t数量\n");
			printf("%s\t%.2lf\t%d\t", result->data.name, result->data.price, result->data.num);
		}
		else
		{
			printf("没有这本书!\n");
		}
		break;
	default:
		printf("【error】\n");
		break;
	}
}










int main()
{
	list = CreateHead();//创建空的链表容器

	ReadInfoFromFile("bookinfo.txt", list);//系统运行之初,就将链表list读入到文件中
	//1.交互界面
	while (1)
	{
		makeMenu();
		KeyDown();
		system("pause"); //暂停批处理文件的处理并显示消息
		system("cls");// 清除屏幕
	}
	
	return 0;
}

在这里插入图片描述

  • 12
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值