【数据结构初阶】--单链表(二)

😘个人主页@Cx330❀

👀个人简介:++一个正在努力奋斗逆天改命的二本觉悟生++

📖个人专栏:《C语言》《LeetCode刷题集》《数据结构-初阶》

前言:上篇博客我们学习了单链表的尾插、头插、尾删、头删四个接口的操作,那么这篇博客将给大家分享剩余单链表的所有的接口,希望大家继续坚持下去🌹🌹🌹


目录

一、单链表的查找

注意事项:

测试结果:

二、单链表在指定位置之前插入元素

注意事项:

测试结果:

三、单链表在指定位置之后插入元素

注意事项:

测试结果:

四、单链表在指定位置删除

注意事项:

测试结果:

五、单链表在指定位置之后删除

注意事项:

测试结果:

六、单链表的销毁

注意事项:

七、全部代码展现

SList.h:

SList.c:

test.c:


一、单链表的查找

和顺序表的学习一样,要想在指定位置插入或者删除数据首先要找到其数据的位置,这里就封装一个函数,对单链表某个数据进行查找

SList.c:

cpp 复制代码
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* pcur = phead;
	while (pcur)
	{
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	//未找到  
	return NULL;
}

注意事项:

如果找到对应的元素,返回指针,找不到就返回空,剩下的也都很简单没有什么特别注意的

test.c:

cpp 复制代码
#include"SList.h"
 
int test1()
{
	//创建节点
	SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));//申请一个节点大小的空间
	SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));
	SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));
	SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));
 
	node1->data = 1;
	node2->data = 2;
	node3->data = 3;
	node4->data = 4;
 
	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = NULL;
	//打印
	SLTNode* plist = node1;//头结点
	SLTPrint(plist);
}
 
void test2()
{
	//头结点
	SLTNode* plist =NULL;
	//尾插
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	//头插
	SLTPushFront(&plist, 5);
	SLTPrint(plist);
	//尾删
	SLTPopBack(&plist);
	SLTPrint(plist);
	//头删
	SLTPopFront(&plist);
	SLTPrint(plist);
	//查找
	SLTNode* pos=SLTFind(plist, 2);
	if (pos == NULL) printf("未找到\n");
	else printf("找到了\n");
 
}
int main()
{
	//test1();
	test2();
	return 0;
}

测试结果:


二、单链表在指定位置之前插入元素

SList.c:

cpp 复制代码
//指定位置之前添加一个节点
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead && pos);
	SLTNode* newnode = SLTBuyNode(x);
	//pos指向头节点
	if (pos == *pphead)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = newnode;
		newnode->next = pos;
	}
}

注意事项:

还是老样子,先进行断言,这里判断如果pos指向的是头节点,直接进行头插,prev是pos前一个节点,让prev->next指向新节点,新节点->next指向pos即可

test.c:

cpp 复制代码
#include"SList.h"
 
int test1()
{
	//创建节点
	SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));//申请一个节点大小的空间
	SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));
	SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));
	SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));
 
	node1->data = 1;
	node2->data = 2;
	node3->data = 3;
	node4->data = 4;
 
	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = NULL;
	//打印
	SLTNode* plist = node1;//头结点
	SLTPrint(plist);
}
 
void test2()
{
	//头结点
	SLTNode* plist =NULL;
	//尾插
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	//头插
	SLTPushFront(&plist, 5);
	SLTPrint(plist);
	//尾删
	SLTPopBack(&plist);
	SLTPrint(plist);
	//头删
	SLTPopFront(&plist);
	SLTPrint(plist);
	//查找
	SLTNode* pos=SLTFind(plist, 3);
	//在指定位置之前插入
	SLTInsert(&plist, pos, 100);
	SLTPrint(plist);
 
}
int main()
{
	//test1();
	test2();
	return 0;
}

测试结果:


三、单链表在指定位置之后插入元素

SList.c:

cpp 复制代码
//在指定位置之后添加一个节点  
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	SLTNode* newnode = SLTBuyNode(x);
	newnode->next = pos->next;
	pos->next = newnode;     
}

注意事项:

当我们要在pos后插入数据,此时我们应该先链接newnode->next=pos->next,因为这样才能保证pos->next可以被找到,若先连接pos和newnode则会导致pos-next找不到

test.c:

cpp 复制代码
#include"SList.h"
 
int test1()
{
	//创建节点
	SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));//申请一个节点大小的空间
	SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));
	SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));
	SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));
 
	node1->data = 1;
	node2->data = 2;
	node3->data = 3;
	node4->data = 4;
 
	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = NULL;
	//打印
	SLTNode* plist = node1;//头结点
	SLTPrint(plist);
}
 
void test2()
{
	//头结点
	SLTNode* plist =NULL;
	//尾插
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	//头插
	SLTPushFront(&plist, 5);
	SLTPrint(plist);
	//尾删
	SLTPopBack(&plist);
	SLTPrint(plist);
	//头删
	SLTPopFront(&plist);
	SLTPrint(plist);
	//查找
	SLTNode* pos=SLTFind(plist, 3);
	////在指定位置之前插入
	//SLTInsert(&plist, pos, 100);
	//SLTPrint(plist);
	//在指定位置之后插⼊数据
	SLTInsertAfter(pos, 100);
	SLTPrint(plist);
 
}
int main()
{
	//test1();
	test2();
	return 0;
}

测试结果:


四、单链表在指定位置删除

SList.c:

cpp 复制代码
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && pos);
	//pos节点刚好是头节点相当于头删
	if (pos == *pphead)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

注意事项:

要特别讨论pos刚好是头结点的情况,直接头删,其它情况先找到pos的前一个结点,最后先用prev链接上pos->nextz再free(pos)

test.c :

cpp 复制代码
#include"SList.h"
 
int test1()
{
	//创建节点
	SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));//申请一个节点大小的空间
	SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));
	SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));
	SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));
 
	node1->data = 1;
	node2->data = 2;
	node3->data = 3;
	node4->data = 4;
 
	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = NULL;
	//打印
	SLTNode* plist = node1;//头结点
	SLTPrint(plist);
}
 
void test2()
{
	//头结点
	SLTNode* plist =NULL;
	//尾插
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	//头插
	SLTPushFront(&plist, 5);
	SLTPrint(plist);
	//尾删
	SLTPopBack(&plist);
	SLTPrint(plist);
	//头删
	SLTPopFront(&plist);
	SLTPrint(plist);
	//查找
	SLTNode* pos=SLTFind(plist, 3);
	////在指定位置之前插入
	//SLTInsert(&plist, pos, 100);
	//SLTPrint(plist);
	//在指定位置之后插⼊数据
	SLTInsertAfter(pos, 100);
	SLTPrint(plist);
	//在指定位置删除
	SLTErase(&plist, pos);
	SLTPrint(plist);
 
}
int main()
{
	//test1();
	test2();
	return 0;
}

测试结果:


五、单链表在指定位置之后删除

SList.c:

cpp 复制代码
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos&&pos->next);
	SLTNode* del = pos->next;
	pos->next = del->next;
	free(del);
	del = NULL;
}

注意事项:

断言pos->next也不能为空,用del存pos->next,再pos链接del->next,free掉del

test.c:

cpp 复制代码
#include"SList.h"
 
int test1()
{
	//创建节点
	SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));//申请一个节点大小的空间
	SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));
	SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));
	SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));
 
	node1->data = 1;
	node2->data = 2;
	node3->data = 3;
	node4->data = 4;
 
	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = NULL;
	//打印
	SLTNode* plist = node1;//头结点
	SLTPrint(plist);
}
 
void test2()
{
	//头结点
	SLTNode* plist =NULL;
	//尾插
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	//头插
	SLTPushFront(&plist, 5);
	SLTPrint(plist);
	//尾删
	SLTPopBack(&plist);
	SLTPrint(plist);
	//头删
	SLTPopFront(&plist);
	SLTPrint(plist);
	//查找
	SLTNode* pos=SLTFind(plist, 2);
	////在指定位置之前插入
	//SLTInsert(&plist, pos, 100);
	//SLTPrint(plist);
	////在指定位置之后插⼊数据
	//SLTInsertAfter(pos, 100);
	//SLTPrint(plist);
	////在指定位置删除
	//SLTErase(&plist, pos);
	//SLTPrint(plist);
	//删除指定位置之后的
	SLTEraseAfter(pos);
	SLTPrint(plist);
}
int main()
{
	//test1();
	test2();
	return 0;
}

测试结果:


六、单链表的销毁

SList.c:

cpp 复制代码
//销毁链表
void SListDestory(SLTNode** pphead)
{
	assert(pphead);
	SLTNode* pcur = *pphead;
	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
}

注意事项:

注意:这里销毁要一个一个的销毁,首先要定义个节点指针next防止销毁过后找不到下一个节点


七、全部代码展现

SList.h:

cpp 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
 
typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;
 
//打印
void SLTPrint(SLTNode* phead);
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x);
//尾删
void SLTPopBack(SLTNode * *pphead);
//头删
void SLTPopFront(SLTNode * *pphead);
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//在指定位置之前插⼊数据
void SLTInsert(SLTNode * *pphead, SLTNode * pos, SLTDataType x);
//在指定位置之后插⼊数据
void SLTInsertAfter(SLTNode * pos, SLTDataType x);
//删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//删除pos之后的结点
void SLTEraseAfter(SLTNode * pos);
//销毁链表
void SListDestroy(SLTNode * *pphead);

SList.c:

cpp 复制代码
#include"SList.h"
 
//打印
void SLTPrint(SLTNode* phead)
{
	SLTNode* pcur = phead;//移动pcur,保证头指针phead位置不变
	while (pcur!= NULL)
	{
		printf("%d -> ", pcur->data);
		pcur = pcur->next;
	}
	printf("NULL\n");
}
//申请新节点
SLTNode* SLTBuyNode(SLTDataType x)
{
	SLTNode* newcode = (SLTNode*)malloc(sizeof(SLTNode));
	newcode->data = x;
	newcode->next = NULL;
	return newcode;
}
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	//申请新节点
	SLTNode* newcode =SLTBuyNode(x);
	//如果头节点为空
	if (*pphead == NULL)
	{
		*pphead = newcode;
	}
	else {
		SLTNode* ptail = *pphead;
		//找到尾节点
		while (ptail->next != NULL)
		{
			ptail = ptail->next;
		}
		//找到了之后链接新节点
		ptail->next = newcode;
	}
}
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	//申请新节点
	SLTNode* newcode = SLTBuyNode(x);
	newcode->next = *pphead;
	*pphead = newcode;
}
//尾删
void SLTPopBack(SLTNode** pphead)
{
	//链表不能为空
	assert(pphead && *pphead);
	//只有一个节点时
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else {
		SLTNode* prev = NULL;
		SLTNode* ptail = *pphead;
		//找到尾结点以及尾节点的前一个节点
		while (ptail->next != NULL)
		{
			prev = ptail;
			ptail = ptail->next;
		}
		//prev ptail
		prev->next = NULL;
		free(ptail);
		ptail = NULL;
	}
}
//头删
void SLTPopFront(SLTNode** pphead)
{
	//链表不能为空
	assert(pphead && *pphead);
	SLTNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* pcur = phead;
	while (pcur)
	{
		if (pcur->data == x)
			return pcur;
		pcur = pcur->next;
	}
	//未找到
	return NULL;
}
//在指定位置之前插⼊数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead && pos);
	SLTNode* newcode = SLTBuyNode(x);
	//pos指向头结点
	if (pos == *pphead)
	{
		SLTPushFront(pphead,x);
	}
	else {
		//找pos的前一个节点
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		//prev newcode pos
		prev->next = newcode;
		newcode->next = pos;
	}
}
//在指定位置之后插⼊数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);
	SLTNode* newcode = SLTBuyNode(x);
	//pos newcode pos->next
	newcode->next = pos->next;
	pos->next = newcode;
}
//删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && *pphead);
	//如果pos刚好就是头结点
	if (pos == *pphead)
	{
		SLTPopFront(pphead);
	}
	else {
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		//prev pos pos->next
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}
//删除pos之后的结点
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos&&pos->next);
	//pos del del->next
	SLTNode* del = pos->next;
	pos->next = del->next;
	free(del);
	del == NULL;
}
//销毁
void SListDestroy(SLTNode** pphead)
{
	assert(pphead);
	SLTNode* pcur = *pphead;
	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
}

test.c:

cpp 复制代码
#include"SList.h"
 
int test1()
{
	//创建节点
	SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));//申请一个节点大小的空间
	SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));
	SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));
	SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));
 
	node1->data = 1;
	node2->data = 2;
	node3->data = 3;
	node4->data = 4;
 
	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = NULL;
	//打印
	SLTNode* plist = node1;//头结点
	SLTPrint(plist);
}
 
void test2()
{
	//头结点
	SLTNode* plist =NULL;
	//尾插
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	//头插
	SLTPushFront(&plist, 5);
	SLTPrint(plist);
	//尾删
	SLTPopBack(&plist);
	SLTPrint(plist);
	//头删
	SLTPopFront(&plist);
	SLTPrint(plist);
	//查找
	SLTNode* pos=SLTFind(plist, 2);
	////在指定位置之前插入
	//SLTInsert(&plist, pos, 100);
	//SLTPrint(plist);
	////在指定位置之后插⼊数据
	//SLTInsertAfter(pos, 100);
	//SLTPrint(plist);
	////在指定位置删除
	//SLTErase(&plist, pos);
	//SLTPrint(plist);
	//删除指定位置之后的
	SLTEraseAfter(pos);
	SLTPrint(plist);
	//销毁
	SListDestroy(&plist);
}
int main()
{
	//test1();
	test2();
	return 0;
}

往期回顾:

【数据结构初阶】--单链表(一)

总结:到此为止单链表我们就已经全部实现完成了,大家还是要养成画图的习惯,并且下去要自己实现一遍,接下来我还会更新双向链表、栈和队列、二叉树等数据结构、希望大家坚持下去,如果文章对你有帮助的话,欢迎评论,点赞,收藏加关注,感谢大家的支持。 🌹🌹🌹

相关推荐
智者知已应修善业5 分钟前
【51单片机6位数码管密码锁】2022-10-15
c语言·经验分享·笔记·单片机·嵌入式硬件·51单片机
Dream it possible!10 分钟前
LeetCode 面试经典 150_数组/字符串_O(1)时间插入、删除和获取随机元素(12_380_C++_中等)(哈希表)
c++·leetcode·面试·哈希表
快去睡觉~15 分钟前
力扣137:只出现一次的数字Ⅱ
数据结构·算法·leetcode
阑梦清川19 分钟前
folo介绍和fluent reader阅读器的使用(RSS订阅技术)
算法
隐-梵40 分钟前
2025年测绘程序设计模拟赛一--地形图图幅编号及图廓点经纬度计算
windows·经验分享·visualstudio·c#
2501_924879361 小时前
密集表盘漏检率↓79%!陌讯多模态融合算法在电表箱状态识别的边缘优化
人工智能·算法·计算机视觉·目标跟踪·智慧城市
Sunlightʊə2 小时前
05.LinkedList与链表
java·数据结构·算法·链表
qq_513970442 小时前
力扣 hot100 Day67
算法·leetcode·职场和发展
chy存钱罐3 小时前
模型拟合问题全解析:从欠拟合、过拟合到正则化(岭回归与拉索回归)
人工智能·算法·机器学习·数据挖掘·回归