单链表的实现

1、单链表的结构:

单链表是一种常用的数据结构,用于存储元素的线性集合,其中每个元素都是一个节点,每个节点指向下一个节点,形成一个链。在单链表中,每个节点通常包含两个部分:一个是存储的数据(或称为值),另一个是指向下一个节点的指针(或链接)。单链表的最后一个节点的指针指向NULL,表示链表的结束。下图是有5个节点的点链表结构示意图:

2、实现单链表的主要函数

实现单链表的增删查改功能,具体包括单链表的前插数据,后插数据,前删数据,后删数据,查找,修改,pos位置的数据插入,pos位置的数据删除,pos位置后的删除,pos位置后的数据插入,以及最后的单链表的销毁。

①单链表的的显示:

通过遍历就能实现,当phead不为空就访问其中的数据并打印,为了视觉效果,使用了->,体现链表链接的感觉。单链表数据显示代码如下:

//单链表显示
void SGLshow(const SGL* phead)//不需要改变头节点,所以可用一级指针,加入const可使phead所指向的值不变
{
	while (phead)//直到移动到NULL停止
	{
		printf("%d->", phead->val);
		phead = phead->next;//每次移动一个节点
	}
	printf("NULL\n");
}

②单链表尾插数据

单链表后插数据,大的逻辑就是判断是否为空链表,如果是空链表就需要对头节点进行移动,不是就不需要动头节点

单链表后插数据代码如下:

//单链表后插数据
void SGLPushback(SGL** pphead, SGLtype val)//如果是空链表就会对头进行改变,所以需要二级指针
{
	assert(pphead);//因为传的是phead的地址,phead的地址不可能为NULL,pphead里存储的是phead的地址
	SGL* newnode = (SGL*)malloc(sizeof(SGL));//开辟一个新节点newnode
	if (newnode == NULL)//newnode为空表示开辟动态内存失败,直接返回,并打印错误信息
	{
		perror("malloc:");
		return;
	}
	newnode->val = val;
	newnode->next = NULL;
	SGL* tail = *pphead;//如果改变*pphead会出现问题,所以定义tail是为了找尾节点
	if (*pphead == NULL)//判断当前链表是否为空,为空就需要移动头节点
	{
		*pphead = newnode;//将头结点的地址用新节点覆盖,也就是让头结点指向新节点
	}
	else//表示不是空链表,直接进行尾插,尾插需要找到尾节点
	{
		while (tail->next)//通过循环找到尾节点
		{
			tail = tail->next;
		}
		//此时tail->next为NULL
		tail->next = newnode;//将newnode的值给tail->next完成链接,实现后插
	}
}

③单链表尾删数据

单链表尾删需要注意该链表是否是空链表,如果是空链表不进行删除操作直接返回。如果为空需要将尾节点的上一个节点的next置NULL,并且需要将尾节点释放(防止内存泄漏)。

单链表尾删数据代码如下: 

//单链表尾删
void SGLPopBack(SGL** pphead)//虽然每次删除不移动头节点,但是当删除到空时,会将头置NULL,所以需要用二级指针
{
	assert(pphead);//因为传的是phead的地址,phead的地址不可能为NULL,pphead里存储的是phead的地址
	if (*pphead == NULL)
	{
		printf("链表为空,不能删除\n");
		return;
	}
	if ((*pphead)->next == NULL)//只有一个节点,表示头删
	{
		free(*pphead);
		*pphead = NULL;
	}
	else//尾删
	{
		SGL* tail = *pphead;//定义tail是为了找尾节点
		while (tail->next->next)//当tail指向的节点的下一个的next为NULL时表示tail处于尾节点的前一个
		{
			tail = tail->next;
		}//此时tail指向的是尾节点的前一个
		free(tail->next);//释放尾节点
		tail->next = NULL;//将为节点置NULL,完成尾删
	}
}

④ 单链表前插数据

单链表前插数据需要注意的是每次进行插入数据都需要对头节点进行移动,将新节点与原来的节点进行链接。

 单链表前插数据代码如下:

//单链表前插数据
void SGLFrontback(SGL** pphead, SGLtype val)//前插每次都需要改变链表头,所以必须要二级指针
{
	assert(pphead);//因为传的是phead的地址,phead的地址不可能为NULL,pphead里存储的是phead的地址
	SGL* newnode = (SGL*)malloc(sizeof(SGL));//开辟一个新节点newnode
	if (newnode == NULL)//newnode为空表示开辟动态内存失败,直接返回,并打印错误信息
	{
		perror("malloc:");
		return;
	}
	newnode->val = val;//插入数据
	newnode->next = *pphead;//将新节点的链接到*pphead
	*pphead = newnode;//将头移动到新节点,完成前插数据
}

 ⑤单链表前删数据

单链表前删数据需要注意链表是否为空,如果链表为空不进行操作直接返回,每次删除都需要移动头节点。

 单链表前删数据代码如下:

//单链表前删
void SGLPopFront(SGL** pphead)//每次前删都要移动头节点,所以必须要二级指针
{
	assert(pphead);//因为传的是phead的地址,phead的地址不可能为NULL,pphead里存储的是phead的地址
	if (*pphead==NULL)
	{
		printf("链表为空,不能删除\n");
		return;
	}
	SGL* del = *pphead;//用del将头位置节点记下来
	*pphead = (*pphead)->next;//将头结点移动到下一个节点
	free(del);//释放节点(这个结点是*pphead移动前的那个节点)
	del = NULL;//将del置NULL,防止出现野指针,这行代码可有可无,因为当出了这个函数del就销毁了
}

⑥单链表查找

单链表查找,需要遍历链表,当找到就返回该节点的地址。

 单链表查找值的位置,代码实现如下:

//单链表查找
//如果找到就该节点的SGL结构体的地址,没找到就返回NULL
SGL* SGLFind(SGL* phead, SGLtype val)//查找不需要对头节点进行改变,所以可以用const修饰,传一级指针
{
	while (phead)//遍历链表
	{
		if (phead->val == val)//当这个节点的val等于val就返回该节点的地址
		{
			return phead;
		}
		phead = phead->next;//每次移动一个节点
	}
	return NULL;//没找到就返回NULL
}

 ⑦单链表修改pos位置的值

想要修改pos位置的值,这个pos是一个结构体地址,所以这个函数需要配合SGLFind的使用,只有,当链表为空,直接返回,当pos为NULL表示输入错误,当pos的值不是该链表中地址则表示链表中没有pos位置。

 单链表修改pos位置的值,代码如下:

//单链表修改
void SGLModify(SGL* phead, SGL* pos,SGLtype val)
{
	if (phead == NULL)//如果链表为空则直接退出
	{
		printf("链表为空,无法修改\n");
		return;
	}
	if (pos == NULL)//如果pos为空直接退出
	{
		printf("pos输入错误\n");
		return;
	}
	SGL* cur = phead;
	while (cur)
	{
		if (cur == pos)//如果当前节点是pos,则将当前节点的值进行修改
		{
			cur->val = val;
			return;//修改完之后直接返回
		}
		cur = cur->next;//进行迭代
	}
    printf("链表中没有pos位置")
}

⑧单链表pos位置插入

当pos为NULL表示头插,需要注意的是当链表为空时,插入需要改变头节点,当链表不为空时,只需要在pos位置插入就行。循环遍历链表,是为了保证当链表中有pos位置,当找到该位置后就进行插入再返回,没找到就会打印链表中没有pos位置

单链表pos位置插入代码如下:

//单链表pos位置插入
void SGLinsert(SGL** pphead, SGL* pos, SGLtype val)//如果该链表为空,则要改变头的位置,所以需要用二级指针
{
	assert(pphead);//因为传的是phead的地址,phead的地址不可能为NULL,pphead里存储的是phead的地址
	SGL* newnode = (SGL*)malloc(sizeof(SGL));//开辟一个新节点newnode
	if (newnode == NULL) //如果newnode为NULL,则表示动态内存空间开辟失败,直接返回,打印相应的错误信息
	{
		perror("malloc");
		return;
	}
	newnode->val = val;//将val存入新节点中
	if (pos == NULL)//如果pos为空则表示头插
	{
		newnode->next = *pphead;//让这个新节点指向头节点
		*pphead = newnode;//再让头节点指向这个新节点,完成头插
	}
	else
	{
		if (*pphead == NULL)//如果链表为空pos为空,则表示链表中没有pos这个位置
		{
			printf("链表中没有pos位置,错误退出\n");
			return;
		}
		else//进行位置插入
		{
			SGL* tail = *pphead;//tail主要是用来找插入的位置的pos
			while (tail)
			{
				if (tail->next == pos)//找到pos的上一个节点tail
				{
					tail->next = newnode;
					newnode->next = pos;
					return;
				}
				tail = tail->next;
			}//当走完还没找到那就表示没有pos的位置
			printf("链表中没有pos的位置\n");
		}
	}
}

⑨单链表pos位置后插

当链表为NULL,pos不为NULL则表示pos错误,当链表为NULL,pos也为NULL则将其头插,当链表不为空,但pos为NULL,则在链表的末尾插入,其他情况循环遍历链表,是为了保证当链表中有pos位置,当找到该位置后就进行插入再返回,循环便利完链表都没返回没找到就会打印链表中没有pos位置。

单链表pos位置后插入代码如下:

//单链表pos位置后插入
void SGLInsertAfter(SGL** pphead, SGL* pos, SGLtype val)
{
	assert(pphead);
	if (*pphead == NULL&&pos!=NULL)//链表为空,但pos不为空则直接退出
	{
		printf("pos错误\n");
		return;
	}
	else if (*pphead == NULL&&pos==NULL)//表示头插
	{
		SGL* newnode = (SGL*)malloc(sizeof(SGL));
		if (newnode == NULL)
		{
			perror("malloc");
			return;
		}
		newnode->next = NULL;
		newnode->val = val;
		*pphead = newnode;
	}
	else if (pos == NULL)//链表不为空,而pos为NULL,表示在最后一个位置插入
	{
		SGL* newnode = (SGL*)malloc(sizeof(SGL));
		if (newnode == NULL)
		{
			perror("malloc");
			return;
		}
		SGL* tail = *pphead;
		while (tail->next)//找最后一个节点
		{
			tail = tail->next;
		}
		newnode->next = NULL;//新节点的next置NULL
		newnode->val = val;//将值存入newnode中
		tail->next = newnode;
	}
	else
	{
		SGL* newnode = (SGL*)malloc(sizeof(SGL));
		if (newnode == NULL)
		{
			perror("malloc");
			return;
		}
		newnode->val = val;
		SGL* tail = *pphead;
		while (tail)//循环遍历链表
		{
			if (tail == pos)
			{
				SGL* tmp = tail->next;
				tail->next = newnode;
				newnode->next = tmp;
				return;
			}
			tail = tail->next;
		}
		printf("链表中没有pos位置\n");
	}
}

⑩单链表pos位置删除 

单链表pos位置删除需要注意链表是否为NULL,如果链表为空则不进行操作打印提示信息直接返回,当链表不为NULL,pos为NULL则打印位置pos错误返回。循环遍历链表,是为了保证当链表中有pos位置,当找到该位置后就将该位置删除再返回,没找到就会打印链表中没有pos位置(这样保证单链表中有pos位置才进行操作,保证不进行越界访问)  

单链表pos位置删除代码如下:

//单链表pos位置删除
void SGLErase(SGL** pphead, SGL* pos)
{
	assert(pphead);
	if (*pphead == NULL)
	{
		printf("链表为空,不能删除\n");
		return;
	}
	if (pos == NULL)
	{
		printf("位置pos错误\n");
		return;
	}
	SGL* tail = *pphead;
	if (*pphead == pos)//表示表示头删
	{
		*pphead = (*pphead)->next;
		free(pos);
		return;
	}
	else//不是头删
	{
		while (tail)
		{
			if (tail->next == pos)//寻找pos的前一个节点
			{
				SGL* tmp = tail->next;
				tail->next = tail->next->next;
				free(tmp);
				tmp = NULL;
				return;
			}
			tail = tail->next;//每次移动一个节点
		}
		// 如果循环结束还没返回,说明没有找到pos位置
		printf("链表中没有pos位置\n");
	}
}

⑪单链表pos位置后删除

当链表为空不能删除,当pos为空则输入pos有误返回。循环遍历链表,是为了保证当链表中有pos位置,当找到该位置后就将其后一个位置删除再返回(需要注意的当pos是最后一个位置不能删除了,因为该函数实现的是pos位置后删除),没找到就会打印链表中没有pos位置(这样保证单链表中有pos位置才进行操作,保证不进行越界访问)  

单链表pos位置后删除代码如下: 

//单链表pos位置后删除
void SGLEraseAfter(SGL** pphead, SGL* pos)
{
	assert(pphead);
	if (*pphead == NULL)//如果链表为空直接退出
	{
		printf("链表为空,不能删除\n");
		return;
	}
	if (pos == NULL)//如果pos为NULL,直接退出
	{
		printf("pos有误\n");
		return;
	}
	SGL* tail = *pphead;
	while (tail)//遍历链表
	{
		if (tail == pos)
		{
			if (tail->next == NULL)
			{
				printf("已经是最后一个了,pos有误\n");
				return;
			}
			SGL* tmp = tail->next;
			tail->next = tail->next->next;
			free(tmp);
			tmp = NULL;
			return;
		}
		tail = tail->next;
	}//当循环结束之后,也就是遍历完链表之后依然没退出就表示链表中没有pos位置
	printf("链表中没有pos\n");
}

 ⑫单链表销毁

单链表的销毁需要通过循环一个一个的将其释放(由于这个链表是通过malloc开辟的动态内存空间,销毁的话需要将其进行free,如不销毁会造成内存泄漏),释放完了之后需要将头指针置NULL

单链表销毁代码如下: 

//单链表销毁
void SGLDestroy(SGL** pphead)//销毁链表需要修改头指向,所以传二级指针
{
	SGL* cur = *pphead;
	SGL* tmp = NULL;//用来存储上一个节点
	while (cur)
	{
		tmp = cur;
		cur = cur->next;
		free(tmp);
	}
	*pphead = NULL;//将头指向NULL
}

 3、单链表代码测试结果如下

前插和后插结果如下:

前删和尾删结果如下:

查找测试结果如下:

 修改测试结果如下:

 位置pos插入和位置pos后插入结果如下:

位置pos删除和位置pos后删除结果如下:

 

销毁链表结果如下:

4、单链表增删查改的完整代码

单链表采用了多文件的形式,test.c主要是用来测试使用的,singlelist.c主要用来实现单链表增删查改以及销毁的功能的,singlelist.h是用来声明函数和定义结构体类型的。

singlelist.h代码如下:

#pragma once
#include<stdio.h>
#include<stdlib.h>//malloc,realloc,calloc,free所需要的头文件
#include<assert.h>
typedef int SGLtype;
//定义链表结构体
typedef struct SGL
{
	SGLtype val;
	struct SGL* next;
}SGL;

//单链表显示
void SGLshow(const SGL* phead);

//单链表后插
void SGLPushback(SGL** pphead,SGLtype val);

//单链表前插
void SGLFrontback(SGL** pphead,SGLtype val);

//单链表前删
void SGLPopFront(SGL** pphead);

//单链表后删
void SGLPopBack(SGL** pphead);

//单链表查找
SGL* SGLFind(SGL* phead, SGLtype val);

//单链表pos位置插入
void SGLInsert(SGL** pphead, SGL* pos, SGLtype val);

//单链表pos位置删除
void SGLErase(SGL** pphead, SGL* pos);

//单链表pos位置后插入
void SGLInsertAfter(SGL** pphead, SGL* pos, SGLtype val);

//单链表pos位置后删除
void SGLEraseAfter(SGL** pphead, SGL* pos);

//单链表修改
void SGLModify(SGL* phead, SGL* pos, SGLtype val);

//单链表销毁
void SGLDestroy(SGL** pphead);

singlelist.c代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include"singlelist.h"
//单链表数据显示
void SGLshow(const SGL* phead)//不需要改变头节点,所以可用一级指针,加入const可使phead所指向的值不变
{
	while (phead)//直到移动到NULL停止
	{
		printf("%d->", phead->val);
		phead = phead->next;//每次移动一个节点
	}
	printf("NULL\n");
}

//单链表尾插数据
void SGLPushback(SGL** pphead, SGLtype val)//如果是空链表就会对头进行改变,所以需要二级指针,不为空不需要改变头
{
	assert(pphead);//因为传的是phead的地址,phead的地址不可能为NULL,pphead里存储的是phead的地址
	SGL* newnode = (SGL*)malloc(sizeof(SGL));//开辟一个新节点newnode
	if (newnode == NULL)//newnode为空表示开辟动态内存失败,直接返回,并打印错误信息
	{
		perror("malloc:");
		return;
	}
	newnode->val = val;//插入数据
	newnode->next = NULL;
	SGL* tail = *pphead;//如果改变*pphead会出现问题,所以定义tail是为了找尾节点
	if (*pphead == NULL)//判断当前链表是否为空,为空就需要移动头节点
	{
		*pphead = newnode;//将头结点的地址用新节点覆盖,也就是让头结点指向新节点
	}
	else//表示不是空链表,直接进行尾插,尾插需要找到尾节点
	{
		while (tail->next)//通过循环找到尾节点
		{
			tail = tail->next;
		}
		//此时tail->next为NULL
		tail->next = newnode;//将newnode的值给tail->next完成链接,实现后插
	}
}

//单链表头插数据
void SGLFrontback(SGL** pphead, SGLtype val)//前插每次都需要改变链表头,所以必须要二级指针
{
	assert(pphead);//因为传的是phead的地址,phead的地址不可能为NULL,pphead里存储的是phead的地址
	SGL* newnode = (SGL*)malloc(sizeof(SGL));//开辟一个新节点newnode
	if (newnode == NULL)//newnode为空表示开辟动态内存失败,直接返回,并打印错误信息
	{
		perror("malloc:");
		return;
	}
	newnode->val = val;//插入数据
	newnode->next = *pphead;//将新节点的链接到*pphead
	*pphead = newnode;//将头移动到新节点,完成前插数据
}

//单链表头删
void SGLPopFront(SGL** pphead)//每次前删都要移动头节点,所以必须要二级指针
{
	assert(pphead);//因为传的是phead的地址,phead的地址不可能为NULL,pphead里存储的是phead的地址
	if (*pphead==NULL)
	{
		printf("链表为空,不能删除\n");
		return;
	}
	SGL* del = *pphead;//用del将头位置节点记下来
	*pphead = (*pphead)->next;//将头结点移动到下一个节点
	free(del);//释放节点(这个结点是*pphead移动前的那个节点)
	del = NULL;//将del置NULL,防止出现野指针,这行代码可有可无,因为当出了这个函数del就销毁了
}

//单链表尾删
void SGLPopBack(SGL** pphead)//虽然每次删除不移动头节点,但是当删除到空时,会将头置NULL,所以需要用二级指针
{
	assert(pphead);//因为传的是phead的地址,phead的地址不可能为NULL,pphead里存储的是phead的地址
	if (*pphead == NULL)
	{
		printf("链表为空,不能删除\n");
		return;
	}
	if ((*pphead)->next == NULL)//只有一个节点,表示头删
	{
		free(*pphead);
		*pphead = NULL;
	}
	else//尾删
	{
		SGL* tail = *pphead;//定义tail是为了找尾节点
		while (tail->next->next)//当tail指向的节点的下一个的next为NULL时表示tail处于尾节点的前一个
		{
			tail = tail->next;
		}//此时tail指向的是尾节点的前一个
		free(tail->next);//释放尾节点
		tail->next = NULL;//将为节点置NULL,完成尾删
	}
}

//单链表pos位置插入
void SGLInsert(SGL** pphead, SGL* pos, SGLtype val)//如果该链表为空,则要改变头的位置,所以需要用二级指针
{
	assert(pphead);//因为传的是phead的地址,phead的地址不可能为NULL,pphead里存储的是phead的地址
	SGL* newnode = (SGL*)malloc(sizeof(SGL));//开辟一个新节点newnode
	if (newnode == NULL) //如果newnode为NULL,则表示动态内存空间开辟失败,直接返回,打印相应的错误信息
	{
		perror("malloc");
		return;
	}
	newnode->val = val;//将val存入新节点中
	if (pos == NULL)//如果pos为空则表示头插
	{
		newnode->next = *pphead;//让这个新节点指向头节点
		*pphead = newnode;//再让头节点指向这个新节点,完成头插
	}
	else
	{
		if (*pphead == NULL)//如果链表为空pos为空,则表示链表中没有pos这个位置
		{
			printf("链表中没有pos位置,错误退出\n");
			return;
		}
		else//进行位置插入
		{
			SGL* tail = *pphead;//tail主要是用来找插入的位置的pos
			while (tail)
			{
				if (tail->next == pos)//找到pos的上一个节点tail
				{
					tail->next = newnode;
					newnode->next = pos;
					return;
				}
				tail = tail->next;
			}//当走完还没找到那就表示没有pos的位置
			printf("链表中没有pos的位置\n");
		}
	}
}


//单链表pos位置删除
void SGLErase(SGL** pphead, SGL* pos)
{
	assert(pphead);
	if (*pphead == NULL)
	{
		printf("链表为空,不能删除\n");
		return;
	}
	if (pos == NULL)
	{
		printf("位置pos错误\n");
		return;
	}
	SGL* tail = *pphead;
	if (*pphead == pos)//表示表示头删
	{
		*pphead = (*pphead)->next;
		free(pos);
		return;
	}
	else//不是头删
	{
		while (tail)
		{
			if (tail->next == pos)//寻找pos的前一个节点
			{
				SGL* tmp = tail->next;
				tail->next = tail->next->next;
				free(tmp);
				tmp = NULL;
				return;
			}
			tail = tail->next;//每次移动一个节点
		}
		// 如果循环结束还没返回,说明没有找到pos位置
		printf("链表中没有pos位置\n");
	}
}


//单链表查找
//如果找到就该节点的SGL结构体的地址,没找到就返回NULL
SGL* SGLFind(SGL* phead, SGLtype val)//查找不需要对头节点进行改变,所以可以用const修饰,传一级指针
{
	while (phead)//遍历链表
	{
		if (phead->val == val)//当这个节点的val等于val就返回该节点的地址
		{
			return phead;
		}
		phead = phead->next;//每次移动一个节点
	}
	return NULL;//没找到就返回NULL
}

//单链表pos位置后插入
void SGLInsertAfter(SGL** pphead, SGL* pos, SGLtype val)
{
	assert(pphead);
	if (*pphead == NULL&&pos!=NULL)//链表为空,但pos不为空则直接退出
	{
		printf("pos错误\n");
		return;
	}
	else if (*pphead == NULL&&pos==NULL)//表示头插
	{
		SGL* newnode = (SGL*)malloc(sizeof(SGL));
		if (newnode == NULL)
		{
			perror("malloc");
			return;
		}
		newnode->next = NULL;
		newnode->val = val;
		*pphead = newnode;
	}
	else if (pos == NULL)//链表不为空,而pos为NULL,表示在最后一个位置插入
	{
		SGL* newnode = (SGL*)malloc(sizeof(SGL));
		if (newnode == NULL)
		{
			perror("malloc");
			return;
		}
		SGL* tail = *pphead;
		while (tail->next)//找最后一个节点
		{
			tail = tail->next;
		}
		newnode->next = NULL;//新节点的next置NULL
		newnode->val = val;//将值存入newnode中
		tail->next = newnode;
	}
	else
	{
		SGL* newnode = (SGL*)malloc(sizeof(SGL));
		if (newnode == NULL)
		{
			perror("malloc");
			return;
		}
		newnode->val = val;
		SGL* tail = *pphead;
		while (tail)
		{
			if (tail == pos)
			{
				SGL* tmp = tail->next;
				tail->next = newnode;
				newnode->next = tmp;
				return;
			}
			tail = tail->next;
		}
		printf("链表中没有pos位置\n");
	}
}

//单链表pos位置后删除
void SGLEraseAfter(SGL** pphead, SGL* pos)
{
	assert(pphead);
	if (*pphead == NULL)//如果链表为空直接退出
	{
		printf("链表为空,不能删除\n");
		return;
	}
	if (pos == NULL)//如果pos为NULL,直接退出
	{
		printf("pos有误\n");
		return;
	}
	SGL* tail = *pphead;
	while (tail)//遍历链表
	{
		if (tail == pos)
		{
			if (tail->next == NULL)
			{
				printf("已经是最后一个了,pos有误\n");
				return;
			}
			SGL* tmp = tail->next;
			tail->next = tail->next->next;
			free(tmp);
			tmp = NULL;
			return;
		}
		tail = tail->next;
	}//当循环结束之后,也就是遍历完链表之后依然没退出就表示链表中没有pos位置
	printf("链表中没有pos\n");
}
//单链表修改
void SGLModify(SGL* phead, SGL* pos,SGLtype val)
{
	if (phead == NULL)//如果链表为空则直接退出
	{
		printf("链表为空,无法修改\n");
		return;
	}
	if (pos == NULL)//如果pos为空直接退出
	{
		printf("pos输入错误\n");
		return;
	}
	SGL* cur = phead;
	while (cur)
	{
		if (cur == pos)//如果当前节点是pos,则将当前节点的值进行修改
		{
			cur->val = val;
			return;//修改完之后直接返回
		}
		cur = cur->next;//进行迭代
	}
}

//单链表销毁
void SGLDestroy(SGL** pphead)//销毁链表需要修改头指向,所以传二级指针
{
	SGL* cur = *pphead;
	SGL* tmp = NULL;//用来存储上一个节点
	while (cur)
	{
		tmp = cur;
		cur = cur->next;
		free(tmp);
	}
	*pphead = NULL;//将头指向NULL
}

test.c文件代码如下: 

#define _CRT_SECURE_NO_WARNINGS 1
#include"singlelist.h"

void test()
{
	SGL* phead = NULL;
	SGLshow(phead);
	SGLPushback(&phead, 1);
	SGLPushback(&phead, 2);
	SGLshow(phead);
	SGLFrontback(&phead, 6);
	SGLFrontback(&phead, 2);
	SGLshow(phead);
	SGLPopFront(&phead);
	SGLshow(phead);
	SGLPopBack(&phead);
	SGLshow(phead);
	SGL* ret = SGLFind(phead, 2);
	printf("ret=%p\n", ret);
	ret = SGLFind(phead, 1);
	printf("ret=%p\n", ret);
	SGLModify(phead, ret, 666);//将1修改为666
	SGLshow(phead);
	SGLInsert(&phead, ret, 100);//在原来1的位置插入,1往后挪一个位置
	SGLshow(phead);
	ret = SGLFind(phead, 100);
	SGLInsertAfter(&phead, ret, 200);//在原来100的位置后插入,100不动
	SGLshow(phead);
	ret = SGLFind(phead, 100);
	SGLErase(&phead, ret);//100的位置删除,也就是删除100
	SGLshow(phead);
	ret = SGLFind(phead, 6);
	SGLEraseAfter(&phead, ret);//6位置后一个删除
	SGLshow(phead);
	SGLDestroy(&phead);//销毁链表
	SGLshow(phead);
}

int main()
{
	test();
	return 0;
}

以上就是单链表实现增删查改的全部介绍,感谢大家观看,如有错误不足之处欢迎大家批判指正

  • 21
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值