单链表(初始化,插入,删除,查找)


链表定义和初始化

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDataType;
typedef struct SListNode
{
	struct SListNode* next;
	SLTDataType data;
}SLTNode;

定义一个链表结构,其中包含指向下一个节点的指针next和存储当前节点值的data

函数声明:

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* SListFind(SLTNode* phead, SLTDataType x);
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
void SListErase(SLTNode** pphead, SLTNode* pos);
void SListInsertAfter(SLTNode* pos, SLTDataType x);
void SListEraseAfter(SLTNode* pos);

链表的打印

void SLTPrint(SLTNode* phead)
{
	SLTNode* cur = phead;
	while (cur)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

用cur指针保存头节点的位置,接着直到cur指针为空打印当前节点的值,并让cur后移。

链表的尾插

SLTNode* BuySLTNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
	
}
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuySLTNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		//找尾
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}

因为涉及到malloc新节点,此功能在后续需要复用,所以封装成函数比较方便

注意尾插这里使用了二级指针,因为要改变的内容是结构体的指针,所以传参时要使用二级指针。尾插需要判断头节点是否为空,如果为空就让newnode成为新的头节点,否则的话需要找到链表的结尾,然后让结尾的next指向newnode。

链表的头插

void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuySLTNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

相比于尾插,头插比较简单(同理,还是需要传二级指针)。头插不需要考虑头节点是否为空。直接让newnode的next指针指向头节点,然后newnode成为新的头节点即可。

链表的尾删

void SLTPopBack(SLTNode** pphead)
{
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next->next != NULL)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}
}

链表的尾删还是先判断头节点的next是否为空,如果为空,直接free掉头节点即可,如果不为空的话,需要找的尾节点,然后free掉置空即可。

链表的头删

void SLTPopFront(SLTNode** pphead)
{
	assert(*pphead);
	SLTNode* first = *pphead;
	*pphead = first->next;
	free(first);
	first = NULL;
}

定义一个first节点来保存头节点,first的next成为新的头节点,然后free掉first节点置空即可。

链表的查找

SLTNode* SListFind(SLTNode* phead, SLTDataType x)
{
	SLTNode *cur= phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

链表的查找返回的是节点的地址(根据值查找,如果有相同的值,返回的是第一个具有该值的节点)

链表的插入(在给定位置之前插入)

void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pos);
	assert(pphead);
	if (*pphead == pos)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* prve = *pphead;
		while (prve->next != pos)
		{
			prve = prve->next;
		}
		SLTNode* newnode = BuySLTNode(x);
		prve->next = newnode;
		newnode->next = pos;
	}
}

链表插入时pos指针即是查找后返回的指针(在pos位置之前插入)。如果插入的位置是头节点,那就是相当于头插,直接复用函数即可。如果不是头节点,那么我们需要去找下一个节点为pos的节点,找到后让prve的next指向newnode,然后newnode的next指向pos就好了。

链表的删除(删除给定位置之前的节点)

void SListErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pos);
	assert(pphead);
	if (*pphead == pos)
	{
		SLTPopFront(&pos);
	}
	else
	{
		SLTNode* prve = *pphead;
		while (prve->next != pos)
		{
			prve = prve->next;
		}
		prve->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

如果删除的位置是头节点的话,直接头删即可。如果不是头节点,还是去找pos的上一个位置,然后直接将prve的next指pos的next就好,接着free掉pos再置空。

链表的插入(在给定位置之后插入)

void SListInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);
	assert(pos->next);
	SLTNode* newnode = BuySLTNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

链表的删除(删除给定位置之后的节点)

void SListEraseAfter(SLTNode* pos)
{
	assert(pos);
	assert(pos->next);
	SLTNode* del = pos->next;
	pos = del->next;
	free(del);
	del = NULL;
}

以上即是单链表的增删查改,希望对大家有帮助。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值