引言:学习完链表,让我们实践一下吧,废话不多说直接上代码
#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;
}