目录
一、单链表的相关函数声明(before.h)
#ifndef _BEFORE_H
#define _BEFORE_H
#define OK 1
#define ERR 0
#define OVERFLOW (-1)
typedef int ElemType;
typedef int status;
typedef struct LNode
{
ElemType data; //每个节点存放一个数据元素
struct LNode *next; //指针指向下一个节点
}LNode,*LinkList;//定义单链表节点类型
//单链表函数声明
status InitList_LinkList(LinkList &L); //初始化建立空表
status ListEmpty_LinkList(LinkList L); //判断单链表是否为空
status ListLength_LinkList(LinkList L); //返回单链表的当前长度
status PriorElem_LinkList(LinkList L,int cur_e,int &pre_e); //返回单链表中指定元素的直接前驱
status NextElem_LinkList(LinkList L,int cur_e,int &next_e); //返回单链表中指定元素的直接后继
status GetElem_LinkList(LinkList L,int i,int &e); //返回指定位置的元素值
status LocateElem_LinkList(LinkList L,ElemType e); //返回指定元素在单链表中的位序
status ListTraverse_LinkList(LinkList &L); //将当前单链表逆置
status ClearList_LinkList(LinkList &L); //将当前单链表清空
status PutElem(LinkList &L,int i,ElemType e); //将指定位置的元素进行替换
status ListInsert_LinkList(LinkList &L,int i,ElemType e); //在单链表中指定位置插入指定元素
status ListDelete_LinkList(LinkList &L,int i,ElemType &e); //在单链表中删除指定位置元素
LinkList List_TailInsert(LinkList &L); //头插法建立单链表
LinkList List_HeadInsert(LinkList &L); //尾插法建立单链表
void PrintList_LinkList(LinkList L); //打印当前单链表
LNode * MaxNum_LinkList(LinkList L); //找到单链表最大值的结点
status DestroyList_LinkList(LinkList &L); //销毁当前单链表
status DeleteNumb_LinkList(LinkList &L,ElemType e,int &chair);//删除指定值结点
//菜单调用函数声明
void Menu_LinkList();
#endif //_BEFORE_H
//
// Created by somewon on 2022/9/28.
//
二、单链表的功能函数定义(func.cpp)
#include <iostream>
#include "before.h"
using namespace std;
//单链表的相关函数的定义
status InitList_LinkList(LinkList &L)
{
L = (LNode *)malloc(sizeof(LNode));
if(L == nullptr) return ERR;
L->next = nullptr;
return OK;
}//初始化一个空单链表
status ListEmpty_LinkList(LinkList L)
{
if(L->next == nullptr) return OK;
else return ERR;
}//判断单链表是否为空
status ListLength_LinkList(LinkList L)
{
LNode *p = L;
int len = 0;
while(p->next != nullptr)
{
len ++;
p = p->next;
}
return len;
}//返回单链表的长度
status PriorElem_LinkList(LinkList L,int cur_e,int &pre_e)
{
LNode *p = L;
if(p->next->data == cur_e) return ERR; //首元素无直接前驱
while(p->next && p->next->data != cur_e)
{
p = p->next;
}
if(p->next)
{
pre_e = p->data;
return OK;
}
else return OVERFLOW; //该元素不在单链表中
}//查找当前元素的直接前驱
status NextElem_LinkList(LinkList L,int cur_e,int &next_e)
{
LNode *p = L->next;
if(p == nullptr) return ERR; //空表无直接后继
while(p->data != cur_e)
{
p = p->next;
if(p->next == nullptr)
{
if(p->data == cur_e) return ERR;
else return OVERFLOW;
}
}
next_e = (p->next)->data;
return OK;
}//返回直接后继的值
status GetElem_LinkList(LinkList L,int i,int &e)
{
if(i < 1) return ERR; //i值不合法
LNode *p = L->next;
int j = 1;
while(p!= nullptr && j<i)
{
p = p->next;
j ++;
}
if(p == nullptr) return ERR;
else e = p->data;
return OK;
}//查找指定位置元素的值
status LocateElem_LinkList(LinkList L,ElemType e)
{
if(ListEmpty_LinkList(L)) return OVERFLOW;
LNode *p = L->next; //从第一个节点开始找
int cnt = 0;
while(p!= nullptr)
{
cnt ++;
if(p->data == e) return cnt;
p = p->next;
}
return ERR;
}
status ListTraverse_LinkList(LinkList &L)
{
if(L->next == nullptr) return ERR;
LNode *t,*s,*a; //定义尾指针、欲插入指针、遍历指针
t = L->next; //尾指针紧贴头指针
s = a = t->next; //从第二个元素开始
t->next = nullptr; //尾指针置空
while(a!= nullptr)
{
a = a->next;
s->next = t;
L->next = s;
t = s;
s = a;
}
return OK;
}
status ClearList_LinkList(LinkList &L)
{
LNode *temp = L->next;
while(temp != nullptr)
{
free(temp);
temp = temp->next;
}
return OK;
}//清空单链表为保留头结点
status PutElem(LinkList &L,int i,ElemType e)
{
LNode *s = L;
if(i < 1) return ERR;
for(int j = 0;j < i;j ++)
{
s = s->next;
if(s == nullptr) return ERR;
}
s->data = e;
return OK;
}//将单链表中对应位置元素替换
status ListInsert_LinkList(LinkList &L,int i,ElemType e)
{
if(i<1) return ERR;
LNode *p; //指针p指向当前扫描到的节点
int j = 0; //当前p指向的是第几个节点
p = L; //L指向头节点,头节点是第0个节点
while(p!= nullptr && j<i-1)
{
p = p->next;
j++;
} //循环找到第i-1个节点
if(p == nullptr) return ERR; //i值不合法
auto s = (LNode *)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s; //将节点s连接到p
return OK; //插入成功
}
status ListDelete_LinkList(LinkList &L,int i,ElemType &e)
{
if(i < 1) return ERR;
LNode *p = L;
int j = 0;
while(p!= nullptr && j<i-1)
{
p = p->next;
j++;
}
if(p == nullptr) return ERR;
if(p->next == nullptr) return OVERFLOW;
LNode *q = p->next; //令q指向被删除节点
e = q->data; //用e返回被删除节点元素的值
p->next = q->next;
free(q);
return OK;
}
LinkList List_TailInsert(LinkList &L)
{
ElemType x;
L = (LinkList)malloc(sizeof(LNode)); //建立头节点
LNode *s,*r = L; //r为表尾指针
cin >> x; //输入节点的值
while(x != -1) //输入-1表示结束
{
s = (LNode *)malloc(sizeof(LNode));
s->data = x;
r->next = s;
r = s; //r指向新的表尾节点
cin >> x;
}
r->next = nullptr; //尾节点指针置空
return L;
}//尾插法建立单链表
LinkList List_HeadInsert(LinkList &L)
{
LNode *s;
ElemType x;
L = (LNode *)malloc(sizeof(LNode));
L->next = nullptr; //均要初始化为NULL
cin >> x;
while(x != -1)
{
s = (LNode *)malloc(sizeof(LNode));
s->data = x;
s->next = L->next;
L->next = s;
cin >> x;
}
return L;
}//头插法建立单链表 (逆置链表的重要思想)
void PrintList_LinkList(LinkList L)
{
LNode *s = L;
if(s->next == nullptr) printf("--当前单链表为空表!\n");
else
{
int numb = 0;
printf("--当前单链表为:\n");
while(s->next != nullptr)
{
s = s->next;
numb ++;
if(numb%7 == 0) printf("\n");
printf("%d\t",s->data);
}
printf("\n");
}
}//打印单链表
LNode * MaxNum_LinkList(LinkList L)
{
LNode *s = L->next; //假设第一个元素的值最大
LNode *p = s->next; //遍历指针
while(p)
{
if(s->data < p->data) s = p;
p = p->next;
}
return s;
}//一遍遍历找到单链表最大值的节点
status DestroyList_LinkList(LinkList &L)
{
LNode *s = L;
while(s)
{
L = L->next;
free(s);
s = L;
}
return OK;
}//销毁单链表(包括头结点都删除)
status DeleteNumb_LinkList(LinkList &L,ElemType e,int &chair)
{
LNode *p = L,*q = L->next;
if(q == nullptr) return ERR; //空表返回错误
while(q)
{
if(q->data == e)
{
p->next = q->next;
free(q);
q = p->next;
chair ++;
}
else
{
p = p->next;
q = q->next;
}
}
return OK;
}//删除指定值
//错误代码暂存
//相关菜单调用
void Menu_LinkList()
{
printf("\t\t\t***********************以下为单链表的菜单*************************\n");
printf("\t\t\t\t1、初始化建立空表 2、头插法建立单链表 \n");
printf("\t\t\t\t3、尾插法建立单链表 4、判断当前单链表是否为空 \n");
printf("\t\t\t\t5、查看当前单链表的长度 6、查看指定元素的直接前驱 \n");
printf("\t\t\t\t7、查看元素的直接后继 8、查看指定位置的元素值 \n");
printf("\t\t\t\t9、查看某元素在单链表中的位序 10、将当前单链表逆置 \n");
printf("\t\t\t\t11、将当前单链表清空 12、将指定位置的元素进行替换 \n");
printf("\t\t\t\t13、指定位置插入元素 14、删除指定位置元素 \n");
printf("\t\t\t\t15、打印当前单链表 16、求当前链表的最大值 \n");
printf("\t\t\t\t17、将当前单链表销毁 18、删除指定元素结点 \n");
printf("\t\t\t\t19、退出操作系统 \n");
printf("\t\t\tTips:只有进行完1、2或1、3操作之后才能进行后续操作,否则程序出现崩溃! \n");
printf("\t\t\t*****************************************************************\n");
}
//
// Created by somewon on 2022/9/28.
//
三、主调函数(main.cpp)
#include <iostream>
#include "before.h"
using namespace std;
int main() {
LinkList L = nullptr; //单链表的声明
LinkList LL = nullptr;
LNode *s; //求最大值的结点声明
ElemType cur_e,pre_e,next_e,e;
int fine,chair,choice; //函数调用返回值的判断变量声明、位序变量声明
do {
Menu_LinkList(); //打印单链表功能选择菜单
printf("请输入你的选择:");
cin >> choice;
switch(choice)
{
case 1:
if(InitList_LinkList(L) == OK) printf("一个空的单链表建立成功!\n");
else printf("初始化空表失败!请再次进行操作!\n");
break;
case 2:
printf("请输入单链表中的元素,输入-1停止添加元素:\n");
List_HeadInsert(L);
printf("头插法创建单链表成功!\n");
PrintList_LinkList(L);
break;
case 3:
printf("请输入单链表中的元素,输入-1停止添加元素:\n");
List_TailInsert(L);
printf("尾插法创建单链表成功!\n");
PrintList_LinkList(L);
break;
case 4:
if(ListEmpty_LinkList(L) == OK) printf("该表目前为空!\n");
else printf("该表不为空!\n");
break;
case 5:
printf("目前该单链表的长度为:%d\n",ListLength_LinkList(L));
break;
case 6:
printf("请输入需要查看直接前驱的元素:");
cin >> cur_e;
pre_e = -1;
fine = PriorElem_LinkList(L,cur_e,pre_e);
if(fine == OK) printf("该元素的直接前驱为:%d\n",pre_e);
else if(fine == ERR) printf("该元素无直接前驱!\n");
else printf("该元素不在单链表中!\n");
break;
case 7:
printf("请输入需要查看直接后继的元素:");
cin >> cur_e;
next_e = -1;
fine = NextElem_LinkList(L,cur_e,next_e);
if(fine == OK) printf("该元素的直接后继为:%d\n",next_e);
else if(fine == ERR) printf("该元素无直接后继!\n");
else printf("该元素不在单链表当中!\n");
break;
case 8:
printf("请输入需要查看的元素值的位序:");
cin >> chair;
e = -1;
GetElem_LinkList(L,chair,e);
if(e == -1) printf("该位序值不合理!请再次进行操作!\n");
else printf("在此单链表中,该位置的元素值为:%d\n",e);
break;
case 9:
printf("请输入需要查看位序的元素:");
cin >> e;
fine = LocateElem_LinkList(L,e);
if(fine == OVERFLOW) printf("该表为空表,无法查看!\n");
else if(fine == ERR) printf("该表中无该元素!\n");
else printf("该元素在单链表中的位序为:%d\n",fine);
break;
case 10:
fine = ListTraverse_LinkList(L);
if(fine == ERR) printf("该表为空!无法逆置!\n");
else
{
printf("逆置此表成功!\n");
PrintList_LinkList(L);
}
break;
case 11:
if(ClearList_LinkList(L) == OK) printf("清空单链表成功!\n");
else printf("清空单链表失败!\n");
break;
case 12:
printf("请输入需要替换值的位序:");
cin >> chair;
printf("请输入需要替换成的元素值:");
cin >> e;
fine = PutElem(L,chair,e);
if(fine == OK)
{
printf("替换成功!\n");
PrintList_LinkList(L);
}
else if(fine == ERR) printf("该位序值不合理!替换不成功!\n");
break;
case 13:
printf("请输入需要插入元素的位序:");
cin >> chair;
printf("请输入插入元素的值:");
cin >> e;
fine = ListInsert_LinkList(L,chair,e);
if(fine == OK)
{
printf("插入成功!\n");
PrintList_LinkList(L);
}
else printf("插入失败!该位序不合理!\n");
break;
case 14:
printf("请输入需要删除元素的位序:");
cin >> chair;
fine = ListDelete_LinkList(L,chair,e);
if(fine == OK)
{
printf("删除成功!\n");
PrintList_LinkList(L);
}
else printf("删除失败!该位序不合理!\n");
break;
case 15:
PrintList_LinkList(L);
break;
case 16:
s = MaxNum_LinkList(L);
if(s->data == -1) printf("该表为空表,无最大值!\n");
else printf("当前单链表中最大值为:%d,该最大值结点地址为%p\n",s->data,s);
break;
case 17:
fine = DestroyList_LinkList(L);
if(fine == OK) printf("当前单链表销毁成功!\n");
else printf("该单链表出现不可抗力元素,销毁失败!\n");
break;
case 18:
printf("请输入需要删除元素的值:");
cin >> e;
chair = 0;
fine = DeleteNumb_LinkList(L,e,chair);
if(fine == OK)
{
printf("删除单链表中该元素成功!共删除了%d个元素!\n",chair);
PrintList_LinkList(L);
}
else printf("该表为空表,无法删除!\n");
break;
case 19:
goto END;
default:
printf("无该操作!请检查系统操作序号是否正确!\n");
}
}while(choice);
END:
printf("谢谢您的使用!欢迎下次光临嘿哈!\n");
return 0;
}
//
//Created by somewon on 2022/9/28.
//
四、运行效果
菜单打印以及具体输出结果
五、运行环境
CLion
Tips:若用的是dev c++,请把nullptr转换为NULL