链表的增删查改等操作(关于数据结构的链表)

本文详细介绍了不带头单向不循环链表的基本概念,包括链表节点结构、初始化、增删查改等操作,并提供了相应的C语言实现。作者强调了实践的重要性,鼓励读者动手尝试和理解这些操作。
摘要由CSDN通过智能技术生成

今天的主题是链表,其实链表说难也难,说简单也简单,完全取决于我们是否完全把它全部理解透。链表其实有很多种,带头的、不带头的,单向的、双向的,循环的、不循环的,组合起来应该是有很多种的(8种)但是我这里只给大家介绍两种,一种是不带头单向不循环链表,也就是大多数书上说的单链表。ok废话少说,直接进入主题:

1.不带头单向不循环链表,我这里就介绍增删查改……等等这几个操作:

首先我们需要有一个单链表进行操作:

typedef int SLNDataType;
//Single List
typedef struct SListNode
{
	SLNDataType val;
	struct SListNode* next;
}SLNode;

这里需要因为链表我们不能保证只能操作整形数据,所以我们直接typedef一下,将来有可以直接修改数据类型,我们知道,链表的每一个节点(结点)都存储了下一个节点的地址,所以我们需要一个结构体指针进行操作:

1.1初始化链表,然后开始尾插链表(包含尾删操作):

void SLTPrint(SLNode* phead)
{
	SLNode* cur = phead;
	while (cur)
	{
		printf("%d->", cur->val);
		cur = cur->next;
	}
	printf("NULL");
	printf("\n");
}
SLNode* Create(SLNDataType x)
{
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	newnode->val = x;
	newnode->next = NULL;
	return newnode;
}
void SLTPushBack(SLNode** pphead, SLNDataType x)
{
	assert(pphead);
	SLNode* newnode = Create(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		//这里是因为我要找到尾节点(结点)才能插入
		SLNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}
void SLTPopBack(SLNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	if ((*pphead)->next == NULL)//一个节点的尾删
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		//SLNode* tail = *pphead;
		//SLNode* prev = NULL;
		//while (tail->next != NULL)
		//{
		//	prev = tail;
		//	tail = tail->next;
		//}
		//free(tail);
		//tail = NULL;
		//prev->next = NULL;
		SLNode* tail = *pphead;
		while (tail->next->next != NULL)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}
}

第一个函数是打印函数,相信大家很好理解,第二个是创作出新节点,方便我们进行尾插操作,

大概就是这样子的,具体的需要大家去好好理解,并且要去查阅资料,方便大家理解尾插操作。

运行测试大概是这样子的:

尾删:

这里大家去测试的代码我就不放出来了,因为这就是一个函数的使用而已。我们继续

1.2头插、头删操作:

void SLTPushFront(SLNode** pphead, SLNDataType x)
{
	assert(pphead);
	SLNode* newnode = Create(x);
	newnode->next = *pphead;
	*pphead = newnode;
}
void SLTPopFront(SLNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	//多个节点+一个节点都可以处理
	//SLNode* next = (*pphead)->next;
	//free(*pphead);
	//*pphead = next;

	SLNode* tem = *pphead;
	*pphead = (*pphead)->next;
	free(tem);
	tem = NULL;
}

这里其实也是一样的,大家要注意我们为什么要使用二级指针进行操作,因为我们知道,在进行相关的操作的时候我们要进行判断,判断pphead是否是空,如果是空的情况下我们要去改变pphead,但是pphead是一个结构体指针,要改变结构体指针,那么我们只能用二级指针操作了。

头插、头删:

1.3指定位置的操作(包括查找、删除):

SLNode* SLTFind(SLNode** pphead, SLNDataType x)
{
	assert(*pphead);
	SLNode* cur = *pphead;
	while (cur)
	{
		if (cur->val == x)
			return cur;
		else
			cur = cur->next;
	}
	return NULL;
}


void SLTInsert(SLNode** pphead,SLNode* pos,SLNDataType x)
{
	assert(pphead);
	assert(*pphead);
	assert(pos);
	//assert((!pos && !(*pphead)) || (*pphead && pos));
	//头插(没有前一个),尾插,中间节点都是要插入,找到前一个
	if (*pphead == pos)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SLNode* newnode = Create(x);
		prev->next = newnode;
		newnode->next = pos;
	}

}
void SLTErase(SLNode** pphead, SLNode* pos)
{
	assert(pphead);
	assert(*pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}
void SLTDestroy(SLNode** pphead)
{
	assert(*pphead);
	while ((*pphead)->next != NULL)
	{
		SLTPopFront(pphead);
	}
	free(*pphead);
	*pphead = NULL;
	//SLNode* cur = *pphead;
	//while (cur)
	//{
	//	SLNode* temp = cur->next;
	//	free(cur);
	//	cur = temp;
	//}
}

请注意:我们这里的指定位置的意思是在指定位置的前面插入

这里我直接把销毁的代码也给出来了,大家好好参考一下

这里的测试代码我应该不需要给出吧(多动手才能成功),大家自己去尝试一下,我都写出函数了,我相信函数的调用大家应该是没问题的!

1.4指定位置的插入、删除(在指定位置的后面插入、删除):

void SLTInsertAfter(SLNode* pos, SLNDataType x)
{
	assert(pos);
	SLNode* newnode = Create(x);
	newnode->next = pos->next;
	pos->next = newnode;
}
void SLTEraseAfter(SLNode* pos)
{
	assert(pos);
	assert(pos->next);
	SLNode* tem = pos->next;
	pos->next = pos->next->next;
	free(tem);
	tem = NULL;
}

这里还是一样提醒大家去多多尝试写代码,相信大家也会成功的!!!!

ps:这里为什么给大家讲这种不带头单项不循环链表吗?因为OJ题大部分都是这个类型的链表,所以我这里介绍的是这种。还有一种双向带头循环链表,我下次讲吧(敬请各位大佬指正,谢谢!)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值