单链表的增删查改(附有代码)

目录

顺序表的缺点:

尾删:

在任意位置插入(pos后):

删除任意位置(pos后):

在任意位置插入(pos前):

销毁链表:

源码

//头文件

//定义文件

//测试文件


顺序表的缺点:


1、尾部插入可以,但是头插或者中间的插入,需要挪动中间的数据,效率底下
2、扩容需要付出代价,例如内存空间的碎片化、以及对空间的利用不充分。比如说只有101个数据,空间满足是100,只能扩容到200,便浪费了大量的空间。扩容的少,便会频繁扩容;扩容的多,导致浪费。

那么为了解决这个问题,就有人提出,能不能我要多少内存我就申请多少内存呢?例如说,我要三个,就给三个,要5个就给5个。但是这些空间并不是连续的。这个时候问题又来了,我要如何管理这些数据的空间呢?原来的数组存储空间是来连续的,但是现在空间是不连续的,也就是说地址是不连续的,也就意味着不能使用下标的方式来解决。怎么办呢?用指针来处理。而这些一个一个的内存空间一般喜欢叫做节点。那么我们怎么找到这些数据呢?一般来说,我们将第一个节点的位置叫做phead,让上一个位置存下一个数据的地址,以此类推,便串起来了

每个节点之间没有关联,是随机分配的。物理上不是线性的,只是逻辑上是我们想象的连续。

每个节点有两个数据,一个存储数据,一个是存储下一个节点的地址

exit(-1)表示异常终止
exit(0)表示正常终止

内部改变外部,一定要解引用,不一定传了指针就会改变

第一个plist是一级指针,要改变就需要传2级指针,2级指针就是一级指针的地址,改变一级指针的地址才能改变一级指针。
改变int,传int*;改变int* ,传int**

改变结构体只需要->操作符即可,->本质上也是一种解引用

只要不是改变当前栈帧的变量,都要通过一个中间量(指针)来修改


尾删:


1、双指针
2、tail->next->next

free本质是释放空间,而不是指向这个空间的指针

尾删除:表为空、表只有一个节点、表有多个节点

在pos之前插入,STL使用的是*SLNode pos,指针位移量

连续定义指针,需要在变量之前加一个*,这是基础语法

带哨兵位的链表:第一个节点不存储有效数据
 

对于单链表来说,只能从前找到后,不能从后找到前面,所以再pos位置后插入比较合适
同理,对于删除pos位置也是一样,删除pos前的位置还需要再找前节点,相对比较麻烦,尽管课可以实现,但是在有更优解的情况下,自然选择简单易行的。


在任意位置插入(pos位置之后):


找到pos位置,记录pos位置的下一个位置,链接
如果pos是最后一个位置,需要特殊处理,但是如果pos不是最后一个节点,就不需要特殊处理,正常处理
如果是插入到pos前一个位置,就需要特别处理,分情况
但是注意:
1、链表为空的时候
2、链表只有一个节点的时候
3、检查pos的位置是否合法


删除任意位置(pos后):


1、pos是头节点,头删
2、pos是最后一个位置,尾删
3、pos是中间节点,正常处理

在任意位置插入(pos前):


1、检查pos节点
2、检查链表
3、只有一个节点,直接删除
4、最后一个节点,和正常删除一样
5、删头,特殊处理

销毁链表:


1、保存下一个节点,删除当前节点
2、最后链表指针置空

源码

//头文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
// slist.h
typedef int SLTDateType;
typedef struct SListNode
{
	SLTDateType data;
	struct SListNode* next;
}SListNode;

// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x);

// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 单链表的尾删
void SListPopBack(SListNode** pplist);
// 单链表头删
void SListPopFront(SListNode** pplist);
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);

// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
void SListInsertAfter(SListNode** pplist,SListNode* pos, SLTDateType x);

// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode** pplist,SListNode* pos);

// 在pos的前面插入
void SLTInsert(SListNode** pplist, SListNode* pos, SLTDateType x);
// 删除pos位置
void SLTErase(SListNode** pplist, SListNode* pos);
void SLTDestroy(SListNode** pplist);

//定义文件

#pragma once
#include"SList.h"

SListNode* BuySListNode(SLTDateType x)
{
	SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));
	if (tmp == NULL)
	{
		perror("malloc fail \n");
		exit(-1);
	}
	SListNode* newnode = tmp;
	newnode->data = x;
	newnode->next = NULL;
}

// 单链表打印
void SListPrint(SListNode* plist)
{
	assert(plist);
	
	SListNode* cur = plist;
	/*while (cur->next != NULL)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");*/

	do
	{
		printf("%d ", cur->data);
		cur = cur->next;
	} while (cur != NULL);
	printf("\n");
}


// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x)
{
	//判断
	assert(pplist);
	if ((*pplist) == NULL)
	{
		(*pplist) = BuySListNode(x);
	}
	else
	{
		SListNode* cur = *pplist;
		while (cur->next != NULL)
		{
			cur = cur->next;
		}
		SListNode* newnode =  BuySListNode(x);
		cur->next = newnode;
	}
}

//单链表头插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
	assert(pplist);
	//判链表为空
	if ((*pplist) == NULL)
	{
		*pplist = BuySListNode(x);
	}
	else
	{
		SListNode* phead = *pplist;
		SListNode* newnode = BuySListNode(x);
		newnode->next = phead;
		*pplist = newnode;
	}

}

// 单链表的尾删
void SListPopBack(SListNode** pplist)
{
	assert(pplist);
	assert(*pplist);
	//只有一个节点
	if ((*pplist)->next == NULL)
	{
		free(*pplist);
		*pplist = NULL;
	}
	else
	{
		//前后指针,保留前一个节点位置,释放最后一个位置
		SListNode* cur = *pplist;
		SListNode* prev = *pplist;
		while (cur->next != NULL)
		{
			prev = cur;
			cur = cur->next;
		}
		free(cur);
		cur = NULL;
		prev->next = NULL;

	}
}


// 单链表头删
void SListPopFront(SListNode** pplist)
{
	assert(pplist);
	//空表
	assert(*pplist);
	//只有一个节点
	if ((*pplist)->next == NULL)
	{
		free(*pplist);
		*pplist = NULL;
	}
	else
	{
		SListNode* first = (*pplist)->next;
		free(*pplist);
		*pplist = first;
	}

}

// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
	//检查空
	assert(plist);

	SListNode* cur = plist;
	while (cur != NULL)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
void SListInsertAfter(SListNode** pplist, SListNode* pos, SLTDateType x)
{
	assert(pplist);
	assert(*pplist);
	assert(pos);
	SListNode* cur = *pplist;
	SListNode* next = cur->next;
	while (cur != pos)
	{
		cur = cur->next;
		next = cur->next;
	}
	if (next == NULL)//尾插
	{
		SListPushBack(pplist,x);
	}
	else
	{
		SListNode * newnode = BuySListNode(x);
		newnode->next = next;
		cur->next = newnode;
	}
}

// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode** pplist, SListNode* pos)
{
	assert(pplist);
	assert(*pplist);
	assert(pos);
	//头删
	if (pos == *pplist)
	{
		SListPopFront(pplist);
		return;
	}
	//尾删
	if (pos->next == NULL)
	{
		SListPopBack(pplist);
		return;
	}
	SListNode* cur = *pplist;
	SListNode* prev = cur;
	SListNode* next = cur->next;
	while (cur != pos)
	{
		prev = cur;
		cur = cur->next;
		next = cur->next;
	}
	prev->next = next;
	free(pos);
	pos = NULL;
}

// 在pos插入
void SLTInsert(SListNode** pplist, SListNode* pos, SLTDateType x)
{
	assert(pplist);
	assert(*pplist);
	assert(pos);
	if(pos == *pplist)
	{
		SListPushFront(pplist,x);
	}
	else
	{
		SListNode* prev = *pplist;
		SListNode* cur = *pplist;
		while(cur != pos)
		{
			prev = cur;
			cur = cur->next;
		}
		SListNode* newnode = BuySListNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}

// 删除pos位置
void SLTErase(SListNode** pplist, SListNode* pos)
{
	assert(pplist);
	assert(*pplist);
	assert(pos);
	if (pos == *pplist)
	{
		SListPopFront(pplist);
		return;
	}
	else
	{
		SListNode* prev = *pplist;
		SListNode* cur = *pplist;
		SListNode* next = cur->next;
		while (cur != pos)
		{
			prev = cur;
			cur = cur->next;
			next = cur->next;
		}
		if (cur->next == NULL)
		{
			SListPopBack(pplist);
			return;
		}
		else
		{
			prev->next = next;
			free(pos);
			pos = NULL;
		}
		
	}
}

void SLTDestroy(SListNode** pplist)
{
	assert(pplist);
	SListNode* cur = *pplist;
	while (cur)
	{
		SListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pplist = NULL;
	printf("SLTDestroy success!\n");
}

//测试文件

#include"SList.h"

SListNode* plist;

//尾插测试
void test1()
{
	SListPushBack(&plist,1);
	SListPushBack(&plist,2);
	SListPushBack(&plist,3);
	SListPushBack(&plist,4);
	SListPushBack(&plist,5);
	SListPrint(plist);
	SLTDestroy(&plist);

}

//头插测试
void test2()
{
	SListPushFront(&plist,1);
	SListPushFront(&plist,2);
	SListPushFront(&plist,3);
	SListPushFront(&plist,4);
	SListPushFront(&plist,5);
	SListPrint(plist);
	SLTDestroy(&plist);

}

//尾删测试
void test3()
{
	SListPushFront(&plist, 1);
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 3);
	SListPushFront(&plist, 4);
	SListPushFront(&plist, 5);
	SListPopBack(&plist);
	SListPopBack(&plist);
	SListPopBack(&plist);
	SListPopBack(&plist);
	SListPopBack(&plist);//打印出问题
	SListPopBack(&plist);//再删出问题
	SListPrint(plist);
	SLTDestroy(&plist);

}

//头删测试
void test4()
{
	SListPushFront(&plist, 1);
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 3);
	SListPushFront(&plist, 4);
	SListPushFront(&plist, 5);
	SListPopFront(&plist);
	SListPopFront(&plist);
	SListPopFront(&plist);
	SListPopFront(&plist);
	SListPrint(plist);
	SLTDestroy(&plist);

}
//查
void test5()
{
	SListPushFront(&plist, 1);
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 3);
	SListPushFront(&plist, 4);
	SListPushFront(&plist, 5);
	SListFind(plist,1);
	SListFind(plist,6);
	SLTDestroy(&plist);

}
//pos后插入
void test6()
{
	SListPushFront(&plist, 1);
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 3);
	SListPushFront(&plist, 4);
	SListPushFront(&plist, 5);
	SListInsertAfter(&plist, SListFind(plist,1),6);
	SListInsertAfter(&plist, SListFind(plist,1),7);
	SListInsertAfter(&plist,SListFind(plist,5),10);
	SListInsertAfter(&plist,SListFind(plist,5),11);
	SLTDestroy(&plist);
	SListPrint(plist);
	
}

//pos后插入
void test7()
{
	SListPushFront(&plist, 1);
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 3);
	SListPushFront(&plist, 4);
	SListPushFront(&plist, 5);
	SListEraseAfter(&plist,SListFind(plist,5));
	SListEraseAfter(&plist,SListFind(plist,1));
	SListEraseAfter(&plist,SListFind(plist,3));
	SListPrint(plist);
	SLTDestroy(&plist);

}

//插pos位置
void test8()
{
	SListPushFront(&plist, 1);
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 3);
	SListPushFront(&plist, 4);
	SListPushFront(&plist, 5);
	SLTInsert(&plist,SListFind(plist,1), -1);
	SLTInsert(&plist,SListFind(plist,5), 6);
	SLTInsert(&plist,SListFind(plist,3), 100);
	SListPrint(plist);
	SLTDestroy(&plist);

}

//删pos位置
void test9()
{
	SListPushFront(&plist, 1);
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 3);
	SListPushFront(&plist, 4);
	SListPushFront(&plist, 5);
	SLTErase(&plist, SListFind(plist,1));
	SLTErase(&plist, SListFind(plist,5));
	SLTErase(&plist, SListFind(plist,3));
	SListPrint(plist);
	SLTDestroy(&plist);
}

int main()
{
	//test1();
	//test2();
	//test3();
	//test4();
	//test5();
	//test6();
	//test7();
	//test8();
	test9();
	return 0;
}

  • 24
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二十5画生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值