基于线性表的图书管理系统(初步)

编译器:VS2022

构建形式:创建项目管理代码

头文件:chainList.h,主要用于存放各种结构体以及函数声明

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<assert.h>
#include<string.h>

typedef struct Book
{
	char ISBN[14];
	char name[20];
	float price;
}Book;

typedef struct Node
{
	Book book;
	struct Node* next;
}Node;

Node* creatHeadNode(void);
Node* creatNewNode(Book book);

void insertBook_end(Node* headNode,Book book);
void insertBook_front(Node* headNode, Book book);
void insertBook_middle(Node* headNode, Book book, Book posBook);

void deleteBook_end(Node* headNode);
void deleteBook_front(Node* headNode);
void deleteBook_middle(Node* headNode, Book posBook);

void traverseList(Node* headNode);
void destroyList(Node* headNode);

int countList(Node* headNode);
Node* searchBook_price(Node* headNode);


源文件:chainList.c和test.c,其中chainList.c用于函数的实现,test.c用于函数的运行

chainList.c内容如下:

#include "chainList.h"

//创建一个表头
Node* creatHeadNode(void)
{
	Node*headNode= (Node*)malloc(sizeof(Node));
	assert(headNode);
	//注:对于表头的数据域不做处理
	headNode->next = NULL;
	return headNode;
}

//创建节点(和创建表头的区别在于对于数据域的处理)
Node* creatNewNode(Book book)
{
	Node* newNode = (Node*)malloc(sizeof(Node));
	assert(newNode);
	newNode->book = book;
	newNode->next = NULL;

}

//链表的遍历
void traverseList(Node* headNode) 
{
	//因为有头链表的表头没有存储数据,所以选择从表头的下一个节点开始遍历
	Node* temp = headNode->next;
	while (temp!=NULL)
	{
		printf("%s %s %.2f\n", temp->book.ISBN, temp->book.name,temp->book.price);
		temp = temp->next;
	}
}

//数据尾插
void insertBook_end(Node* headNode,Book book)
{
	Node* temp = headNode;
	//找到尾部(尾部节点的特点是什么?tailNode->next=NULL(而不是tailNode=NULL,修改的时候也是如此))
	while (temp->next != NULL)
	{
		temp = temp->next;
	}
	//创建一个新的节点
	Node*newNode = creatNewNode(book);
	//与原来的链表相连接
	temp ->next = newNode;
}

//数据头插
void insertBook_front(Node* headNode, Book book)
{
	//先保存原来的第一个节点
	Node* temp = headNode->next;
	//创建新的节点插入到头指针的后面
	headNode->next = creatNewNode(book);
	//将原来的第一个节点接到插入的节点的后面
	headNode = headNode->next;
	headNode->next = temp;
}

//在指定数据的位置前插(posBook是目标书的位置)
void insertBook_middle(Node* headNode, Book book, Book posBook)
{
	//首先第一步是找到posBook所在的节点位置,然后记录其前驱
	//所以需要两个指针,并排走(因为链表是有方向的)
	
	//创建好这个新的节点
	Node* newNode = creatNewNode(book);
	//目标位置
	Node* posNode = headNode->next;
	//目标位置的前驱
	Node* preNode = headNode;
	//注意结构体的比较不能直接算数比较(><)[注意,这里存在短路现象,自己看看结尾]
	//寻找指定的节点的写法非常固定的,需要记住
	while (posNode->next!= NULL && strcmp(posNode->book.ISBN,posBook.ISBN)!=0)
	{
		//并排向后走
		posNode = posNode->next;
		preNode = preNode->next;
	}
	//短路现象补充判断
	if (strcmp(posNode->book.ISBN, posBook.ISBN) != 0)
	{
		printf("没有发现该书,请重新确认\n");
	}
	//找到了该节点,连接
	else
	{
		preNode ->next= newNode;
		newNode->next=posNode;
	}
}

//数据尾删(注意不能传入空的链表(只有表头))
void deleteBook_end(Node*headNode)
{
	//依旧是前驱加后继双节点
	Node* posNode = headNode->next;
	Node* preNode = headNode;
	//尾节点的特点是其指针域的值为NULL
	while (posNode->next!= NULL)
	{
		posNode = posNode->next;
		preNode = preNode->next;
	}
	free(posNode);
	preNode->next = NULL;
}

//数据头删(注意不能传入空的链表(只有表头))
void deleteBook_front(Node* headNode)
{
	//依旧是前驱加后继双节点
	Node* posNode = headNode->next;
	Node* preNode = headNode;
	//将头指针和第二个相连
	preNode->next = posNode->next;
	//释放第一个节点
	free(posNode);
}

//指定位置删除:将指定位置节点删除
void deleteBook_middle(Node* headNode,Book posBook)
{
	//目标位置
	Node* posNode = headNode->next;
	//目标位置的前驱
	Node* preNode = headNode;
	//注意结构体的比较不能直接算数比较(><)[注意,这里存在短路现象,自己看看结尾]
	//寻找指定的节点的写法非常固定的,需要记住
	while (posNode->next != NULL && strcmp(posNode->book.ISBN, posBook.ISBN) != 0)
	{
		//并排向后走
		posNode = posNode->next;
		preNode = preNode->next;
	}
	//短路现象补充判断
	if (strcmp(posNode->book.ISBN, posBook.ISBN) != 0)
	{
		printf("没有发现该书,请重新确认\n");
	}
	//找到了该节点,删除
	else
	{
		preNode->next = posNode->next;
		free(posNode);
	}

}

//链表的销毁
void destroyList(Node* headNode)
{
	//从表头的下一个,也就是第一个节点开始删除
	Node* posNode = headNode->next;
	//当第一个节点的指针域不为空(最终删到只有头结点和第一个节点)的时候,持续删除
	while (posNode->next!= NULL)
	{
		deleteBook_end(headNode);
	}
	//最后释放表头和第一个节点
	free(posNode);
	free(headNode);
}

//节点个数的统计
int countList(Node* headNode)
{
	int count = 0;
	Node* posNode = headNode->next;
	while (posNode != NULL)
	{
		posNode = posNode->next;
		count++;
	}
	return count;
}

//数据的查找(查找最高价格),返回价格最高的书的节点(只能查找其中的一个,查询所有的将在后续完善)
Node* searchBook_price(Node* headNode)
{
	Node* posNode = headNode->next;
	Node* temp = posNode;
	//一直向后,直到最后一个节点停止,最终posNode是最后一个节点
	while (posNode->next != NULL)
	{
		//如果有节点的价格大于temp节点中的价格,则更新数据
		if (posNode->book.price > temp->book.price)
		{
			temp = posNode;
		}
		posNode = posNode->next;
	}
	return temp;
}

test.c用于函数测试,可以根据需要进行更改,测试,由于在编写的过程中我已验证过其余函数的正确性,代码中只验证了searchBook_price函数。希望读者在代码移植后对其中的函数进行一一测试,防止编译器不同所带来的差异。

#include"chainList.h"

int main()
{
	Node* headNode = creatHeadNode();

	Book book0 = { "0000","NNN",12.5 };
	Book book1 = { "1111","mmm",22.5 };
	Book book2 = { "2222","ppp",32.5 };
	Book book3 = { "3333","qqq",42.5 };
	Book book4 = { "4444","ccc",52.5 };

	insertBook_end(headNode, book0);
	insertBook_end(headNode, book1);
	insertBook_end(headNode, book2);
	insertBook_end(headNode, book3);
	traverseList(headNode);
	printf("------------------------\n");
	Node*p = searchBook_price(headNode);
	printf("%f", p->book.price);
	return 0;
}

对于pdf中的实验要求,只写了一部分,还有待完善,将在后续更新...

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
线性表是一种简单、常用的数据结构,可以用来构建图书管理系统。下面是一种基于线性表图书管理系统的设计: 1. 数据结构 我们可以用一个线性表来表示所有的图书,每个元素包含以下信息: - 书名 - 作者 - 出版社 - 出版日期 - ISBN号 - 借出日期 - 借阅人 同时,我们还需要一个记录用户信息的线性表,每个元素包含以下信息: - 姓名 - 学号 - 借书数量 - 借阅的书籍的ISBN号列表 2. 功能实现 基于上述数据结构,我们可以实现以下功能: - 添加图书:将新的图书信息添加到图书线性表中。 - 删除图书:根据ISBN号,从图书线性表中删除相应的图书信息。 - 修改图书信息:根据ISBN号,修改图书线性表中相应的图书信息。 - 借阅图书:将借阅人信息添加到相应的图书元素中,并将借阅人的学号和所借图书的ISBN号添加到用户信息线性表中。 - 归还图书:将相应的图书元素中的借阅人信息删除,并将用户信息线性表中相应的借阅信息删除。 - 查询图书:根据书名、作者、出版社、出版日期等信息,从图书线性表中查询相应的图书信息。 - 查询借阅情况:根据学号,从用户信息线性表中查询相应的借阅情况。 3. 用户界面 最后,我们需要一个用户界面来方便用户使用图书管理系统。用户界面可以提供以下功能: - 显示所有图书信息。 - 显示所有用户信息。 - 提供添加、删除、修改、借阅、归还、查询图书和查询借阅情况的按钮。 - 提供搜索框,方便用户根据书名、作者、出版社、出版日期等信息查询图书。 - 提供借阅历史记录,方便用户查看自己的借阅历史。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值