正文
本程序使用带头节点的单链表存储结构实现,共有六个基本功能,完成对信息链表的增删改查。
注意
/*
1.对于结构体或自定义元素类型最好传地址,传值的话会涉及到内存拷贝。
2.函数memset()与memcpy()是c/c++中的内存初始化和内存拷贝函数,数据元素是结构体变量时也适用,初始化或者赋值时不需要对结构体内数据元素进行一个一个的赋值。
函数解释:
(1).void *memset(void *s, int ch, size_t n);
将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
(2).void *memcpy(void *destin, void *source, unsigned n);
从源source所指的内存地址的起始位置开始拷贝n个字节到目标destin所指的内存地址的起始位置中。
3.system(“color f1”);//调整背景颜色与字符颜色
头文件是 #include<windows.h>
**/
部分功能运行展示
1.插入信息功能:
2.清除信息功能
3.退出系统功能
所包含头文件及结构体的定义
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<windows.h>
int seat;//定义一个全局变量,保存结点的位置序号
//定义结构体数据元素。
typedef struct{
int num; //定义图书编号。
char name[31]; //定义图书名字。
}ElemType;
//定义链表节点结构体。
typedef struct LNode{
ElemType data; // 加入一个自定义数据元素 用来存放数据。
struct LNode *next; //定义一个节点类型指针,后续让它指向该节点的下一结点。
}LNode,*LinkList;
自定义函数
// 初始化链表LL,返回值:成功-头结点的地址,失败-NULL。
LNode *InitList();
// 销毁链表LL。
//注意链表的销毁操作最后需要将链表指针也置空。
void DestroyList(LinkList LL);
// 清空链表。
//清空链表需要保留头指针。
void ClearList(LinkList LL);
//打印链表。
void PrintList(LinkList LL);
//在链表中第seat个位置插入元素,返回值:成功-1,失败-0。
int InsertList(LinkList LL,unsigned int seat,ElemType *ee);
//在链表第一个位置添加元素,返回值:成功-1,失败-0。
int PushFront(LinkList LL,ElemType *ee);
//在链表最后一个位置添加元素。
void PushBack(LinkList LL,ElemType *ee);
//在链表中第seat个位置删除元素,返回值:成功-1,失败-0。
int DeleteList(LinkList LL,unsigned int seat,ElemType *ee);
// 通过元素信息删除表中节点
void DeleteNode(LinkList LL,ElemType *ee);
//根据编号寻找结点位置,返回值:成功-结点位置,失败-0。
int LocateList(LinkList LL,int ii);
主函数
int main()
{
LinkList LL;//声明一个链表。
LL=NULL;
ElemType ee;//声明一个自定义元素。
LL=InitList();//对链表进行初始化。
int choose,ii; //choose保存主要功能选择号码,ii用于保存次要功能选择号码。
char name_tmp[31];
system("color f1");//调整背景颜色与字符颜色
//条件始终为真的循环。
while(1){
printf("\n");
printf("---------------------------------\n");
printf("* 欢迎使用图书管理系统 *\n");
printf("* 1.查看所有图书信息 *\n");
printf("* 2.添加图书信息 *\n");
printf("* 3.删除图书信息 *\n");
printf("* 4.修改图书信息 *\n");
printf("* 5.清空图书信息 *\n");
printf("* 6.退出系统 *\n");
printf("---------------------------------\n");
printf("\n");
printf("请选择功能选项(1-6):\n");
scanf("%d",&choose);
switch(choose){
case 1:
PrintList(LL); //打印链表。
break;
case 2:
printf("请插入图书信息(输入为0时停止插入):\n");
printf("请输入要插入的图书编号:\n");
scanf("%d",&ee.num);
printf("请输入要插入的图书名:\n");
scanf("%s",&name_tmp); strcpy(ee.name,name_tmp);
while(ee.num!=0)
{
printf("请选择要添加图书信息的位置(1-添加在第一个,2-添加在末尾,3-自定义位置):\n");
scanf("%d",&ii);
if(ii == 1) PushFront(LL,&ee);//在链表第一个位置添加元素 。
if(ii == 2) PushBack(LL,&ee);//在链表最后一个位置添加元素。
if(ii == 3)
{
printf("请输入插入位置:\n");
scanf("%d",&seat);
InsertList(LL,seat,&ee);//在链表中第ii个位置插入元素,返回值:成功-1,失败-0。
}
printf("请插入图书信息(输入为0时停止插入):\n");
printf("请输入要插入的图书编号:\n");
scanf("%d",&ee.num);
printf("请输入要插入的图书名:\n");
scanf("%s",&name_tmp); strcpy(ee.name,name_tmp);
}
PrintList(LL);
break;
case 3:
printf("请选择想要进行的图书信息删除操作(1-通过编号删除,2-自定义位置):\n");
scanf("%d",&ii);
if(ii == 1)
{
memset(&ee,0,sizeof(ElemType));//通过该函数将ee初始化。
printf("请输入要删除的图书编号:\n");
scanf("%d",&ee.num);
DeleteNode(LL,&ee); // 通过元素信息删除表中节点
}
if(ii == 2)
{
printf("请输入删除位置:\n");
scanf("%d",&seat);
DeleteList(LL,seat,&ee);//在链表中第ii个位置删除元素,返回值:成功-1,失败-0。
}
PrintList(LL);
break;
case 4:
printf("请输入要修改图书的编号:\n");
scanf("%d",&ii);
seat=LocateList(LL,ii);//根据编号寻找结点位置,返回值:成功-结点位置,失败-0。
if(seat!=0)
{
printf("请输入更新后的图书编号:\n");
scanf("%d",&ee.num);
printf("请输入更新后的图书名:\n");
scanf("%s",&name_tmp); strcpy(ee.name,name_tmp);
ReplaceList(LL,seat,&ee);//在链表中第ii个位置替换元素。
PrintList(LL);
}
break;
case 5:
ClearList(LL);//清空链表。
break;
case 6:
DestroyList(LL); LL=NULL;//销毁链表并将指针置空。
printf("成功退出!欢迎再次使用图书管理系统!\n");
return 0;
default:
printf("选择的功能选项不存在!功能选项范围值在1-6之间!\n");
break;
}
}
}
完整代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<windows.h>
int seat;//定义一个全局变量,保存结点的位置序号
//定义结构体数据元素。
typedef struct{
int num; //定义图书编号。
char name[31]; //定义图书名字。
}ElemType;
//定义链表节点结构体。
typedef struct LNode{
ElemType data; // 加入一个自定义数据元素 用来存放数据。
struct LNode *next; //定义一个节点类型指针,后续让它指向该节点的下一结点。
}LNode,*LinkList;
// 初始化链表LL,返回值:成功-头结点的地址,失败-NULL。
LNode *InitList();
// 销毁链表LL。
//注意链表的销毁操作最后需要将链表指针也置空。
void DestroyList(LinkList LL);
// 清空链表。
//清空链表需要保留头指针。
void ClearList(LinkList LL);
//打印链表。
void PrintList(LinkList LL);
//在链表中第seat个位置插入元素,返回值:成功-1,失败-0。
int InsertList(LinkList LL,unsigned int seat,ElemType *ee);
//在链表第一个位置添加元素,返回值:成功-1,失败-0。
int PushFront(LinkList LL,ElemType *ee);
//在链表最后一个位置添加元素。
void PushBack(LinkList LL,ElemType *ee);
//在链表中第seat个位置删除元素,返回值:成功-1,失败-0。
int DeleteList(LinkList LL,unsigned int seat,ElemType *ee);
// 通过元素信息删除表中节点
void DeleteNode(LinkList LL,ElemType *ee);
//根据编号寻找结点位置,返回值:成功-结点位置,失败-0。
int LocateList(LinkList LL,int ii);
//在链表中第seat个位置替换元素。
void ReplaceList(LinkList LL,unsigned int seat,ElemType *ee);
int main()
{
LinkList LL;//声明一个链表。
LL=NULL;
ElemType ee;//声明一个自定义元素。
LL=InitList();//对链表进行初始化。
int choose,ii; //choose保存主要功能选择号码,ii用于保存次要功能选择号码。
char name_tmp[31];
system("color f1");//调整背景颜色与字符颜色
//条件始终为真的循环。
while(1){
printf("\n");
printf("---------------------------------\n");
printf("* 欢迎使用图书管理系统 *\n");
printf("* 1.查看所有图书信息 *\n");
printf("* 2.添加图书信息 *\n");
printf("* 3.删除图书信息 *\n");
printf("* 4.修改图书信息 *\n");
printf("* 5.清空图书信息 *\n");
printf("* 6.退出系统 *\n");
printf("---------------------------------\n");
printf("\n");
printf("请选择功能选项(1-6):\n");
scanf("%d",&choose);
switch(choose){
case 1:
PrintList(LL); //打印链表。
break;
case 2:
printf("请插入图书信息(输入为0时停止插入):\n");
printf("请输入要插入的图书编号:\n");
scanf("%d",&ee.num);
printf("请输入要插入的图书名:\n");
scanf("%s",&name_tmp); strcpy(ee.name,name_tmp);
while(ee.num!=0)
{
printf("请选择要添加图书信息的位置(1-添加在第一个,2-添加在末尾,3-自定义位置):\n");
scanf("%d",&ii);
if(ii == 1) PushFront(LL,&ee);//在链表第一个位置添加元素 。
if(ii == 2) PushBack(LL,&ee);//在链表最后一个位置添加元素。
if(ii == 3)
{
printf("请输入插入位置:\n");
scanf("%d",&seat);
InsertList(LL,seat,&ee);//在链表中第ii个位置插入元素,返回值:成功-1,失败-0。
}
printf("请插入图书信息(输入为0时停止插入):\n");
printf("请输入要插入的图书编号:\n");
scanf("%d",&ee.num);
printf("请输入要插入的图书名:\n");
scanf("%s",&name_tmp); strcpy(ee.name,name_tmp);
}
PrintList(LL);
break;
case 3:
printf("请选择想要进行的图书信息删除操作(1-通过编号删除,2-自定义位置):\n");
scanf("%d",&ii);
if(ii == 1)
{
memset(&ee,0,sizeof(ElemType));//通过该函数将ee初始化。
printf("请输入要删除的图书编号:\n");
scanf("%d",&ee.num);
DeleteNode(LL,&ee); // 通过元素信息删除表中节点
}
if(ii == 2)
{
printf("请输入删除位置:\n");
scanf("%d",&seat);
DeleteList(LL,seat,&ee);//在链表中第ii个位置删除元素,返回值:成功-1,失败-0。
}
PrintList(LL);
break;
case 4:
printf("请输入要修改图书的编号:\n");
scanf("%d",&ii);
seat=LocateList(LL,ii);//根据编号寻找结点位置,返回值:成功-结点位置,失败-0。
if(seat!=0)
{
printf("请输入更新后的图书编号:\n");
scanf("%d",&ee.num);
printf("请输入更新后的图书名:\n");
scanf("%s",&name_tmp); strcpy(ee.name,name_tmp);
ReplaceList(LL,seat,&ee);//在链表中第ii个位置替换元素。
PrintList(LL);
}
break;
case 5:
ClearList(LL);//清空链表。
break;
case 6:
DestroyList(LL); LL=NULL;//销毁链表并将指针置空。
printf("成功退出!欢迎再次使用图书管理系统!\n");
return 0;
default:
printf("选择的功能选项不存在!功能选项范围值在1-6之间!\n");
break;
}
}
}
// 初始化链表LL,返回值:成功-头结点的地址,失败-NULL。
LNode *InitList()
{
LNode *head=(LNode*)malloc(sizeof(LNode)); //定义一个头结点。
if(head == NULL) return NULL; //内存分配失败。
head->next=NULL; // 头结点的下一结点置空。
return head; // 返回头结点。
}
// 销毁链表LL。
//注意链表的销毁操作最后需要将链表指针也置空。
void DestroyList(LinkList LL)
{//本函数的链表指针置空操作需要在函数外部完成。
LNode *pp;
while(LL!=NULL)
{
pp=LL->next; //pp指针保存下一结点的信息
free(LL); //依次释放节点内存
LL=pp; //LL指针指向下移一结点
}
}
// 清空链表。
//清空链表需要保留头指针。
void ClearList(LinkList LL)
{
if(LL == NULL) { printf("图书管理信息表不存在!\n"); return; }//检查是否传入空指针。
LNode *tmp1,*tmp2;
tmp1=LL->next;//从头结点的下一结点开始遍历。
while(tmp1!=NULL)
{
tmp2=tmp1->next; //tmp2指针保存下一结点的信息。
free(tmp1); //依次释放节点内存。
tmp1=tmp2; //tmp1指针指向下移一结点。
}
LL->next=NULL; //将指向头结点下一结点的指针置空,防止出现野指针。
printf("所有信息已经清空!\n");
}
//打印链表。
void PrintList(LinkList LL)
{
if(LL == NULL) { printf("图书管理信息表不存在!\n"); return; }//检查是否传入空指针。
if(LL->next == NULL) { printf("图书管理信息表为空!\n"); return; }
LNode *tmp=LL->next; //从头结点的下一个结点开始打印。
seat=1; //从第一个位置开始 。
printf("---------------------------------\n");
printf("序号\t编号\t书名\n");
while(tmp!=NULL)
{
printf("%d\t%d\t%s\n",seat,tmp->data.num,tmp->data.name); //逐行打印信息。
seat++; //序号加1。
tmp=tmp->next; //指针指向下一结点 。
}
printf("---------------------------------\n");
}
//在链表中第seat个位置插入元素,返回值:成功-1,失败-0。
int InsertList(LinkList LL,unsigned int seat,ElemType *ee)
{
if( (LL == NULL) && (ee == NULL) ) { printf("图书管理信息表不存在或者书籍信息未建立成功!\n"); return 0; } //检查是否传入空指针。
if(seat<1) { printf("插入位置不合法!输入位置序号应大于0!\n"); return 0; }
LNode *pp=LL;
int ii=0;
//需要找到要插入位置的上一个结点。
while( (pp!=NULL) && (ii<seat-1) )
{
pp=pp->next;
ii++;
}
LNode *tmp=(LNode*)malloc(sizeof(LNode)); //分配一个结点用于数据元素的插入。
if(tmp == NULL) { printf("内存不足!无法插入图书信息\n"); return 0; } //内存不足,分配失败。
//结点插入操作 。
tmp->next=pp->next;
pp->next=tmp;
//插入结点数据。
memcpy(&tmp->data,ee,sizeof(ElemType));
printf("图书信息插入成功!\n");
return 1;
}
//在链表第一个位置添加元素,返回值:成功-1,失败-0。
int PushFront(LinkList LL,ElemType *ee)
{
return InsertList(LL,1,ee); //可以直接调用插入函数,插入位置为1。
}
//在链表最后一个位置添加元素。
void PushBack(LinkList LL,ElemType *ee)
{
if( (LL == NULL) && (ee == NULL) ) { printf("图书管理信息表不存在或者书籍信息未建立成功!\n"); return; } //检查是否传入空指针。
LNode *pp=LL;
while(pp->next!=NULL) pp=pp->next; //指针依次往后继结点移动,直到找到最后一个结点。
LNode *tmp=(LNode*)malloc(sizeof(LNode)); //分配一个结点用于数据元素的插入。
if(tmp == NULL) { printf("内存不足!无法插入图书信息\n"); return; } //内存不足,分配失败。
//结点插入操作 。
tmp->next=NULL; // 所插入结点为最后一个结点,后继指针指向空。
pp->next=tmp;
//插入结点数据。
memcpy(&tmp->data,ee,sizeof(ElemType));
printf("图书信息插入成功!\n");
}
//在链表中第seat个位置删除元素,返回值:成功-1,失败-0。
int DeleteList(LinkList LL,unsigned int seat,ElemType *ee)
{
if( (LL == NULL) && (ee == NULL) ) { printf("图书管理信息表不存在或图书信息输入未成功!\n"); return 0; } //检查是否传入空指针。
if(seat<1) { printf("删除位置不合法!输入位置序号应大于0!\n"); return 0; }
LNode *pp=LL; //定义一个指针指向头结点。
int ii=0;
//需要找到要删除位置的上一个结点。
while( (pp!=NULL) && (ii<seat-1) )
{
pp=pp->next;
ii++;
}
//因为是删除所找到结点的下一结点,如果下一结点不存在则返回失败。
if(pp->next == NULL) { printf("删除位置不合法!应小于图书信息表长度!\n"); return 0; }
LNode *tmp=pp->next; //定义一个指针使其指向需要删除的结点。
pp->next=tmp->next; // pp的后继指针指向所要删除结点的后一个结点。
free(tmp); //释放所要删除的结点内存。
printf("图书信息删除成功!\n");
return 1;
}
// 通过元素信息删除表中节点
void DeleteNode(LinkList LL,ElemType *ee)
{
if( (LL == NULL) && (ee == NULL) ) { printf("图书管理信息表不存在或图书信息输入未成功!\n"); return; } //检查是否传入空指针。
seat=LocateList(LL,ee->num);
DeleteList(LL,seat,ee);
}
//根据编号寻找结点位置,返回值:成功-结点位置,失败-0。
int LocateList(LinkList LL,int ii)
{
if(LL == NULL) { printf("图书管理信息表不存在!\n"); return 0; }//检查是否传入空指针。
LNode *pp=LL->next; //从第一个结点开始查找。
seat=1; //序号从1开始。
while(pp!=NULL)
{
if(pp->data.num == ii) return seat;
pp=pp->next;
seat++;
}
printf("未找到图书信息!\n");
return 0;
}
//在链表中第seat个位置替换元素。
void ReplaceList(LinkList LL,unsigned int seat,ElemType *ee)
{
if( (LL == NULL) && (ee == NULL) ) { printf("图书管理信息表不存在或图书信息输入未成功!\n"); return; } //检查是否传入空指针。
LNode *tmp=LL->next;
int kk=1;
//找到替换位置的结点。
while( (tmp!=NULL) && (kk<seat) )
{
tmp=tmp->next;
kk++;
}
if(tmp == NULL) { printf("更新位置不合法!应小于图书信息表长度!\n"); return; }
memset(&tmp->data,0,sizeof(ElemType));//清空原结点内容。
memcpy(&tmp->data,ee,sizeof(ElemType));//添加修改的内容。
printf("图书信息更新成功!\n");
}
结束语
因为本程序使用到的是基本的链表操作,仅实现了链表的增删改查操作,所以部分功能还可以进一步完善,各位uu如果在代码中发现了有不正确的地方,还请指正,谢谢!