该图书管理系统使用哈希表的数据结构来存放图书信息,使用链地址的方法解决冲突问题,用哈希映射函数来决定每个节点插入的位置。
构建哈希表存放数据节点
构建结构体存放图书的基本信息类型
构建链表节点存放每个图书信息
项目结构
library.h
#ifndef _LIBRARY_H
#define _LIBRARY_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define SIZE 27
typedef struct library
{
char name[20]; //书名
int id; //书号
char address[30]; //存放地址
int date; //入库日期
char status[20]; //状态
}data_type;
//定义链表节点
typedef struct linknode
{
data_type data; //数据域
struct linknode *pNext; //指针域
}LinkNode;
//定义哈希表
typedef struct hash
{
LinkNode *pArr[SIZE]; //存放链表首地址
int count; //有效图书的个数
int libraryid;
}Hash;
enum res
{
MALLOCERROR =-4,
HASHNULL,
ERROR,
POSERROR,
OK
};
//创建hash表
Hash *createHash(void);
//哈希映射函数
int hashFun(char *name);
//插入元素
int InsertItemHash(Hash *pHash, data_type item);
//显示
int showHash(Hash *pHash);
//删除(根据书名)
int DeleteItemHash(Hash *pHash, char *name, data_type *pData);
//更新(根据书名)
int AlterLibraryMessage(Hash *pHash, data_type NewData);
//查询书信息(根据书名)
int searchLibraryMessage(Hash *pHash, char *name);
//借出
int LendItemHash(Hash *pHash, char *name);
//下载
int DownloadItem(Hash *pHash);
//上传
int UplodeItem(Hash *pHash);
//销毁哈希表
int destroyHash(Hash **ppHash);
#endif
library.c
这里的哈希映射函数使用书名的首地址作为主Key,大写字母和小写字母分别减去65和97映射结构体数组的0~25位,其余特殊字符存入第27位。
使用文件IO操作文件,将每次插入的图书信息存入文件内。
#include "../include/library.h"
//创建哈希表
Hash *createHash(void)
{
Hash *pHash = NULL;
pHash = (Hash *)malloc(sizeof(Hash));
if(NULL == pHash)
{
perror("malloc error");
return NULL;
}
return pHash;
}
//哈希映射函数
int hashFun(char *name)
{
int index = 0;
int first = name[0];
if(first > 96 && first < 123)
{
index = first - 97;
}
else if(first > 64 && first < 107)
{
index = first - 65;
}
else
{
index = 26;
}
return index;
}
//插入元素
int InsertItemHash(Hash *pHash, data_type NewData)
{
//入参判断
if(NULL == pHash)
{
return HASHNULL;
}
//创建新节点
LinkNode *pNew = (LinkNode *)malloc(sizeof(LinkNode));
if(NULL == pNew)
{
return MALLOCERROR;
}
memset(pNew,0,sizeof(LinkNode));
//把数据存入新节点的数据域
pNew->data = NewData;
//用哈希映射函数确定节点插入位置
int index = 0;
index = hashFun(NewData.name);
//判断该位置是否有头节点,如果无则创建
LinkNode *pHead = NULL;
if(NULL == pHash->pArr[index])
{
pHash->pArr[index] = (LinkNode *)malloc(sizeof(LinkNode));
pHead = pHash->pArr[index];
if(NULL == pHead)
{
return MALLOCERROR;
}
memset(pHead,0,sizeof(LinkNode));
pHead->pNext = pNew;
}
else
{
pHead = pHash->pArr[index];
pNew->pNext = pHead->pNext;
pHead->pNext = pNew;
}
pHash->count ++;
return OK;
}
//显示
int showHash(Hash *pHash)
{
//入参判断
if(NULL == pHash)
{
return HASHNULL;
}
//定义一个游标
LinkNode *pTmp = NULL;
int i = 0;
for(i = 0; i < SIZE; i++)
{
if(pHash->pArr[i] != NULL)
{
pTmp = pHash->pArr[i]->pNext;
while(pTmp != NULL)
{
printf("=============================\n");
printf("书名:%s\n",pTmp->data.name);
printf("书号:%d\n",pTmp->data.id);
printf("存放地址:%s\n",pTmp->data.address);
printf("入库日期:%d\n",pTmp->data.date);
printf("状态:%s\n",pTmp->data.status);
printf("=============================\n");
pTmp = pTmp->pNext;
}
}
}
return OK;
}
//删除
int DeleteItemHash(Hash *pHash, char *name, data_type *pData)
{
//入参判断
if(NULL == pHash)
{
return HASHNULL;
}
//判断书名是否合法
int index = hashFun(name);
if((index < 0) || (index > 26))
{
return ERROR;
}
//定义一个游标
LinkNode *pDel = NULL;
//根据书名寻找要删除的节点
if(NULL == pHash->pArr[index])
{
return POSERROR;
}
pDel = pHash->pArr[index];
while(1)
{
pDel = pDel->pNext;
if(strcmp(name,pDel->data.name) == 0)
{
*pData = pDel->data;
strcpy(pDel->data.status,"丢失");
printf("删除成功!\n");
break;
}
else if(NULL == pDel->pNext)
{
printf("查无此书!\n");
return ERROR;
}
}
pHash->count --;
return OK;
}
//更新图书信息
int AlterLibraryMessage(Hash *pHash, data_type NewData)
{
//入参判断
if(NULL == pHash)
{
return HASHNULL;
}
//定义一个游标
LinkNode *pTmp = NULL;
//根据哈希映射函数寻找要更新的节点
int index = hashFun(NewData.name);
if(NULL == pHash->pArr[index])
{
return POSERROR;
}
pTmp = pHash->pArr[index];
while(1)
{
pTmp = pTmp->pNext;
if(strcmp(pTmp->data.name,NewData.name) == 0)
{
pTmp->data = NewData;
printf("修改成功!\n");
break;
}
else if(NULL == pTmp->pNext)
{
printf("查无此书!\n");
return ERROR;
}
}
return OK;
}
//借出
int LendItemHash(Hash *pHash, char *name)
{
//入参判断
if(NULL == pHash)
{
return HASHNULL;
}
//判断书名是否合法
int index = hashFun(name);
if((index < 0) || (index > 26))
{
return ERROR;
}
//定义一个游标
LinkNode *pDel = NULL;
//根据书名寻找要借出的节点
if(NULL == pHash->pArr[index])
{
return POSERROR;
}
pDel = pHash->pArr[index];
while(1)
{
pDel = pDel->pNext;
if(strcmp(name,pDel->data.name) == 0)
{
strcpy(pDel->data.status,"借出");
printf("借出成功\n");
break;
}
else if(NULL == pDel->pNext)
{
printf("查无此书!\n");
return ERROR;
}
}
return OK;
}
//查询书信息
int searchLibraryMessage(Hash *pHash, char *name)
{
//入参判断
if(NULL == pHash)
{
return HASHNULL;
}
//定义一个游标
LinkNode *pTmp = NULL;
//根据哈希映射函数寻找要查询的节点
int index = hashFun(name);
if(NULL == pHash->pArr[index])
{
return POSERROR;
}
pTmp = pHash->pArr[index];
while(1)
{
pTmp = pTmp->pNext;
if(strcmp(pTmp->data.name,name) == 0)
{
printf("=============================\n");
printf("书名:%s\n",pTmp->data.name);
printf("书号:%d\n",pTmp->data.id);
printf("存放地址:%s\n",pTmp->data.address);
printf("入库日期:%d\n",pTmp->data.date);
printf("状态:%s\n",pTmp->data.status);
printf("=============================\n");
printf("查询成功!\n");
break;
}
else if(NULL == pTmp->pNext)
{
printf("查无此书!\n");
return ERROR;
}
}
return OK;
}
//下载
int DownloadItem(Hash *pHash)
{
//入参判断
if(NULL == pHash)
{
return HASHNULL;
}
int fr = 0;
int rd_data = 0;
data_type item;
fr = open("../data/LibraryMassage.txt",O_RDONLY);
if(fr < 0)
{
perror("oper error");
}
else
{
while(1)
{
rd_data = read(fr,&item,sizeof(data_type));
if(0 == rd_data)
{
printf("导入完毕!\n");
break;
}
else if(rd_data < 0)
{
printf("导入失败!\n");
return ERROR;
}
else
{
InsertItemHash(pHash,item);
}
}
}
close(fr);
return OK;
}
//上传
int UplodeItem(Hash *pHash)
{
//入参判断
if(NULL == pHash)
{
return HASHNULL;
}
int wr_count;
int fr = 0;
printf("正在更新数据\n");
fr = open("../data/LibraryMassage.txt",O_WRONLY | O_CREAT | O_TRUNC,0664);
if(fr < 0)
{
perror("open error");
}
else
{
LinkNode *pTmp = NULL;
int i = 0;
for(i = 0; i < SIZE; i++)
{
if(pHash->pArr[i] != 0)
{
pTmp = pHash->pArr[i]->pNext;
while(NULL != pTmp)
{
//写入
int wr_count = write(fr,&pTmp->data,sizeof(data_type));
if(0 == wr_count)
{
printf("未成功写入!\n");
return ERROR;
}
else if(wr_count < 0)
{
perror("写入失败");
return ERROR;
}
pTmp = pTmp->pNext;
}
}
}
}
close(fr);
return OK;
}
//销毁哈希表
int destroyHash(Hash **ppHash)
{
//入参判断
if(NULL == *ppHash)
{
return HASHNULL;
}
//定义两个游标
LinkNode *pTmp = NULL;
LinkNode *pDel = NULL;
int i = 0;
for(i = 0; i < SIZE; i++)
{
pTmp = (*ppHash)->pArr[i];
while(pTmp != NULL)
{
pDel = pTmp->pNext;
pTmp = pTmp->pNext;
free(pDel);
pDel = NULL;
}
}
free(*ppHash);
*ppHash = NULL;
return OK;
}
main.c
#include "../include/library.h"
void menu(void)
{
printf("*******************************\n");
printf("* 1------------------增加图书 *\n");
printf("* 2------------------删除图书 *\n");
printf("* 3------------------更新图书 *\n");
printf("* 4------------------查询图书 *\n");
printf("* 5------------------显示图书 *\n");
printf("* 6------------------借出 *\n");
printf("* 7------------------下载 *\n");
printf("* 8------------------上传 *\n");
printf("*-1------------------退出 *\n");
printf("*******************************\n");
}
int main(void)
{
Hash *pHash = NULL;
pHash = createHash();
data_type item;
data_type pData;
data_type NewData;
int libraryid = 0;
int ret = 0;
char name[20] = {'\0'};
int op = 0;
while(1)
{
menu();
scanf("%d",&op);
if(-1 == op)
{
break;
}
switch(op)
{
//插入元素
case 1:
printf("请输入书的名字:\n");
scanf("%s",item.name);
printf("请输入书的存放地址\n");
scanf("%s",item.address);
printf("请输入书的入库时间(例:20221525)\n");
scanf("%d",&item.date);
item.id = item.date * 100 + pHash->libraryid + 1;
pHash->libraryid++;
printf("请输入书的状态\n");
scanf("%s",item.status);
ret = InsertItemHash(pHash,item);
if(ret < 0)
{
printf("增加失败!\n");
}
else
{
printf("增加成功!\n");
}
break;
//删除
case 2:
printf("请输入要删除的书名:\n");
scanf("%s",name);
ret = DeleteItemHash(pHash,name,&pData);
if(ret < 0)
{
printf("删除失败!\n");
}
break;
//更新
case 3:
printf("请输入要更改的书名\n");
scanf("%s",NewData.name);
printf("请输入书的存放地址\n");
scanf("%s",NewData.address);
printf("请输入书的入库时间(例:20221525)\n");
scanf("%d",&NewData.date);
NewData.id = item.date * 100 + libraryid + 1;
libraryid++;
printf("请输入书的状态\n");
scanf("%s",NewData.status);
ret = AlterLibraryMessage(pHash,NewData);
if(ret < 0)
{
printf("修改失败!\n");
}
break;
//查询
case 4:
printf("请输入你要查询的书的名称:\n");
scanf("%s",name);
ret = searchLibraryMessage(pHash,name);
if(ret < 0)
{
printf("查询失败!\n");
}
break;
//显示
case 5:
printf("所有的图书:\n");
showHash(pHash);
break;
//借出
case 6:
printf("请输入要借出的书名:\n");
scanf("%s",name);
ret = LendItemHash(pHash,name);
if(ret < 0)
{
printf("借出失败!\n");
}
break;
case 7:
DownloadItem(pHash);
break;
case 8:
UplodeItem(pHash);
break;
}
}
destroyHash(&pHash);
return 0;
}