文章目录
前言
编程实现单向链表的基本操作的实现包含1.插入元素2.删除元素3.获取第i个结点的数据元素4.判断元素是否存在5.获取某个元素的下一个元素
1.编程实现单向链表的基本操作
代码如下(示例):
//Author:北硝 Date:2023.3.29
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<string.h>
//本程序主要功能说明:
// 单链表(带头结点)基本操作实现
// 1.插入结点 2.删除结点 3.获取i元素 4.判断元素是否存在 5.获取某个元素的下一个元素
//程序返回结构 定义 1成功 0失败
#define Status int
#define OK 1
#define ERROR 0
#define OVERFLOW -2 //申请不到内存时 用-2表示
//自定义的数据元素,
typedef struct {
char name[10]; //假设暂时只用姓名和手机号
char phone[20]; //假设暂时只用姓名和手机号
} ElemType;
//单链表 结点定义
typedef struct LNode {
ElemType data;
struct LNode* next;
}LNode, * LinkList;
//基本操作1:插入结点
Status ListInsert_L(LinkList L, int i, ElemType e) {
LNode *p = L;//先把头指针复制出来
int j = 0;
while (p && j < i - 1) {
p = p->next;
++j;
} //寻找到要插入位置的前一个结点
if (!p || j > i - 1) {
return ERROR;
}
//开辟新结点
LNode* s = (LinkList)malloc(sizeof(LNode));
if (s == NULL) {
exit(OVERFLOW);
}
s->data = e;
s->next = p->next;
p->next = s; //注意这两句的顺序;
return OK;
}
//基本操作2:删除结点
Status ListDelete_L(LinkList L, int i) {
LNode* p = L;
int j = 0;
while (p->next && j < i - 1) {
p = p->next;
++j;
}//p指向要删除位置的前一个结点
//如果最后一个结点都不是你要找的结点的前一个结点
if (!(p->next) || j > i - 1) {
return ERROR;
}
LNode* q = p->next;//q此时指向要删除的结点
p->next = q->next;
free(q); //最后释放掉该结点的内存
return OK;
}
//基本操作3:获取第i个结点
Status GetElem_L(LinkList L, int i, ElemType* e) {
LNode* p = L->next;//指向了第一个数据元素
int j = 1;
while (p && j < i) {
p = p->next;
++j;
}
//p为NULL 表示是 把结点遍历完了
//j=i 表示到了要获取的位置
//此时p也指向了第i个元素
if (!p || j > i) {
return ERROR; //遍历完不存在第i个元素
}
*e = p->data;
return OK;
}
int ElemIsEqual(ElemType e1, ElemType e2);
//基本操作4:单向链表 判断元素e是否存在
// 存在时,返回下标位置
// 不存在时,返回0
int LocateElem_L(LinkList L, ElemType e) {
ElemType temp_e;//接收遍历时候的元素
LNode* p = L->next;//指向了第一个数据元素
int j = 1; //表示当前处理的序号
//遍历一遍L,依次比较
while (p) {
temp_e = p->data;
if (ElemIsEqual(temp_e, e)) {
return j; //直接返回序号
}
p = p->next;
j++;
}
//遍历完还没有找到就返回 0
return 0;
}
//基本操作5:获取某个元素的下一个元素
Status NextElem(LinkList L, int cur_e, ElemType* next_e) {
LNode* p = L->next;//指向了第一个数据元素
int j = 1;
while (p && j < cur_e + 1) {
p = p->next;
++j;
}
//p为NULL 表示是 把结点遍历完了
//j=i 表示到了要获取的位置
//此时p也指向了第i个元素
if (!p || j > cur_e + 1) {
return ERROR; //遍历完不存在第i个元素
}
*next_e = p->data;
return OK;
}
//
// 以下几个函数是自定义的, 用于打印数据元素和界面的,不属于线性表的基本操作
//功能:打印某个数据元素
void pintElem(ElemType e) {
printf("{%s, %s}\r\n", e.name, e.phone);
}
//功能:遍历打印一下当前的单向链表:
void printList(LinkList L) {
LNode* p = L->next;//p先指向第一个数据结点
if (L->next == NULL) {
return;//为空时可以不用展示
}
printf("当前单向链表所有元素为:\r\n");
while (p) {
//打印每一个数据元素
pintElem(p->data);
p = p->next;
}
printf("\r\n\n");//打印完 跟后面内容最好分隔开
}
//功能:打印主界面菜单
void printMenu(void) {
printf("\t\t*****单向链表的基本操作语句实现*****\r\n");
printf("\t\t*********** 1. 插入元素e ***********\r\n");
printf("\t\t*********** 2. 删除第i个元素 ***********\r\n");
printf("\t\t*********** 3. 获取第i个元素 ***********\r\n");
printf("\t\t*********** 4. 判断元素e是否存在 ***********\r\n");
printf("\t\t*********** 5. 获取某个元素的下一个元素 ***********\r\n");
}
//从控制台输入获取某个元素e
void getElemFormConsole(ElemType* e) {
printf("请输入姓名 手机号(回车表示结束):\r\n");
scanf_s("%s", e->name, 20);
scanf_s("%s", e->phone, 20);
}
//判断两个元素是否相等:
//相等返回1 不相等返回0
int ElemIsEqual(ElemType e1, ElemType e2) {
if (strcmp(e1.name, e2.name) == 0 &&
strcmp(e1.phone, e2.phone) == 0) {
return 1;
}
return 0;
}
//菜单的功能1:插入:
//就是从控制台接收要插入的位置i 和 元素e 并调用基本功能插入
void FunctionNo1(LinkList L) {
ElemType e;//用于接收要插入的元素e
int i;//用于接收要插入的位置
system("cls");//清屏
printf("请输入要插入的位置(回车表示结束):\r\n");
scanf_s("%d", &i, 5);
getElemFormConsole(&e);
//调用基本操作语句 插入
int result = ListInsert_L(L, i, e);
if (result != OK) {
printf("插入操作失败!");
system("pause");
}
}
//菜单的功能2:删除:
//就是从控制台接收要删除的位置i 并调用基本功能删除
void FunctionNo2(LinkList L) {
int i;//用于接收要删除的位置
system("cls");//清屏
printf("请输入要删除的位置(回车表示结束):\r\n");
scanf_s("%d", &i, 5);
//调用基本操作语句 删除
int result = ListDelete_L(L, i);
if (result != OK) {
printf("删除操作失败!");
system("pause");
}
}
//菜单的功能3:获取第i个元素
//就是从控制台接收要 查询的序号, 并调用基本功能获取第i元素
void FunctionNo3(LinkList L) {
int i;//用于接收要查询的序号
ElemType e;//用于接收查询到的元素
system("cls");//清屏
printf("请输入要查询的位置(回车表示结束):\r\n");
scanf_s("%d", &i, 5);
//调用基本操作语句 获取第i元素
int result = GetElem_L(L, i, &e);
if (result != OK) {
printf("查询操作失败!");
system("pause");
return;
}
//查出来打印一下
printf("\r\n查询出来的第 %d 个元素为:", i);
pintElem(e);
system("pause");//暂停一下 让用户能看到查询的结果,再下一步
}
//菜单的功能4:判断元素e是否存在
//就是从控制台接收要 查询的元素,并调用基本功能判断是否存在
void FunctionNo4(LinkList L) {
ElemType e;//用于接收要查询的元素e
system("cls");//清屏
//接收要查询的元素e
getElemFormConsole(&e);
//调用基本操作语句 LocateElem_L
int result = LocateElem_L(L, e);
if (!result) {
//不存在
printf("所找的元素e 不存在!");
}
else {
printf("所找的元素e 存在! 位置是第%d个", result);
}
system("pause");
}
//菜单的功能5:获取某个元素的下一个元素
//就是从控制台接收要 查询的序号, 并调用基本功能获取某个元素的下一个元素
void FunctionNo5(LinkList L) {
int i;//用于接收要查询的序号
ElemType e;//用于接收查询到的元素
system("cls");//清屏
printf("请输入要查询的位置(回车表示结束):\r\n");
scanf_s("%d", &i, 5);
//调用基本操作语句 获取第i元素
int result = NextElem(L, i, &e);
if (result != OK) {
printf("查询操作失败!");
system("pause");
return;
}
//查出来打印一下
printf("\r\n查询出来的第 %d 个元素为:", i + 1);
pintElem(e);
system("pause");//暂停一下 让用户能看到查询的结果,再下一步
}
//自定义几个功能代码
#define FUNCTION01 1
#define FUNCTION02 2
#define FUNCTION03 3
#define FUNCTION04 4
#define FUNCTION05 5
void main() {
LinkList L; //只是定义了一个头指针
int selectFun = 0;
//先创建一个头结点,头结点用户不用感知
//开辟一个新结点:作为头结点
LNode* s = (LinkList)malloc(sizeof(LNode));
if (s == NULL) {
exit(OVERFLOW);
}
s->next = NULL;
//s->data 不用处理。 不用它
L = s; //头指针 指向头结点
while (1) {
system("cls");//清屏
printList(L);//先展示一下当前的表内容
printMenu();//展示一下 主菜单
printf("请输入你的选择:(回车表示结束)\r\n");
scanf_s("%d", &selectFun, 5);
switch (selectFun) {
case FUNCTION01:
//选择功能1时
FunctionNo1(L);
break;
case FUNCTION02:
//选择功能2时
FunctionNo2(L);
break;
case FUNCTION03:
//选择功能3时
FunctionNo3(L);
break;
case FUNCTION04:
//选择功能4时
FunctionNo4(L);
break;
case FUNCTION05:
//选择功能5时
FunctionNo5(L);
break;
default:;
}
}
}
总结
编程实现单向链表的五个基本操作的实现