【C语言】线性表之单向链表

目录

前言

链表的概念 

单向链表节点的语法结构 

单向链表的实现 

创建链表节点

尾部插入的实现

尾部删除的实现。 

头部插入的实现 

第一种写法

第二种写法 

头部删除的实现 

第一种写法

第二种写法 

随机删除

随机插入 (插入在目标节点前)

打印整个链表 

修改节点

总结 


前言

这篇文章是无头单项非循环链表,后面会跟一篇有头双向循环链表的,还希望能得到同志们的支持。

这是我的数据结构和算法专栏,希望各位同志、大佬能够点点赞

https://blog.csdn.net/zhengzjm/category_12170458.html

链表的概念 

概念:链表是一种 物理存储结构上非连续 、非顺序的存储结构,数据元素的 逻辑顺序 是通过链表 中的指针链接 次序实现的 。

单向链表节点的语法结构 

由上图可知,链表的元素(节点)由两个部分组成,一部分是数据域,用来存放数据,另一部分是指针域,用来连接链表。

将链表节点想象成一个个纸片,由指针将他们串起来。

typedef int SLTDataType;//链表数据域的数据类型,方便直接修改

typedef struct SListNode
{
	SLTDataType data;//数据域
	SListNode* next;//指针域,用来连接节点(链表元素)
}SListNode;

单向链表的实现 

我们理想中的链表示意图:

创建链表节点

创建节点就是开辟一个链表节点类型的空间,形参为需要添加的数据,返回值为新开辟的这块空间的地址。

SListNode* BuyNode(SLTDataType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}

尾部插入的实现

先判断节点是否存在,不存在则让指向首节点的指针指向新开辟的空间,存在则利用循环找到末节点,将新开辟的节点同末节点连接起来。

void PushBack(SListNode**pplist,SLTDataType x)
{
	SListNode* cur = *pplist;
	//如果指向第一个链表的指针为空指针,说明该链表尚无节点。
	if (*pplist == NULL)
	{
		*pplist = BuyNode(x);
	}
	else
	{
		while (cur->next!=NULL)//找到末端链表
		{
			cur=cur->next;
		}
		cur->next = BuyNode(x);
	}
}

尾部删除的实现。 

有几种情况:没有节点、只有一个节点、多个节点。使用if进行判断。

对于多个节点,我们使用两个指针,一个是prev,一个是tail。tail用来找末端节点(侦察兵),prev用来指向tail指向节点的上一个节点,使用while循环来寻找末端节点,找到时先释放掉末端节点上一节点的next所指向的节点(tail所指向的节点\prev所指向的节点中的next所指向的节点),再将prev所指向的节点中的next指针改为空指针。

void PopBack(SListNode** pplist)
{
	if (*pplist == NULL)
	{
		perror("PopBack");
        return;
	}
	else if ((*pplist)->next == NULL)
	{
		free(*pplist);
		*pplist = NULL;
	}
	else
	{
		SListNode* prev = NULL;
		SListNode* tail = *pplist;
		while (tail->next!=NULL)
		{
			prev = tail;
			tail = tail->next;
		}
		
		free(prev->next);
		prev->next = NULL;
	}
}

头部插入的实现 

第一种写法

用指针first将原首节点的地址存放起来,令pplist指向新首节点,新首节点中的next指向原首节点。


void PushFront(SListNode** pplist, SLTDataType x)
{
		SListNode* first = *pplist;
		*pplist = BuyNode(x);
		(*pplist)->next= first;
}

第二种写法 

先创建新节点,令新节点的next指向原首节点,再令pplist指向新首节点。

void PushFront(SListNode** pplist, SLTDataType x)
{
	SListNode* newnode = BuyNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

头部删除的实现 

第一种写法

先将原首节点地址存起来,然后令pplist指向新的首节点,释放掉原首节点。

void PopFront(SListNode** pplist)
{
	SListNode* first = *pplist;
	*pplist = (*pplist)->next;
	free(first);
}

第二种写法 

用next保存新首节点的地址,释放掉原首节点,令pplist指向新首节点。

void PopFront(SListNode** pplist)
{
	SListNode* next = (*pphead)->next;
	free(*pphead);

	*pphead = next;
}

随机删除

同样需要侦察兵cur,用来寻找我们要删除的目标节点,prev用来指向目标节点的上一节点,如果要删除的节点是首节点,我们之间复用上面的头部删除就行了。另外的情况通过while寻找,当找到时跳出循环,将目标节点的上一节点同目标节点的下一节点连接,释放掉目标节点。 

void SListErase(SListNode** pplist, SLTDataType pos)
{
	SListNode* prev = NULL;
	SListNode* cur = *pplist;
	if (pos == (*pplist)->data)
	{
		PopFront(pplist);
	}
	else
	{
		while (cur->data != pos)
		{
			prev = cur;
			cur = cur->next;
		}
		prev->next = cur->next;
		free(cur);
	}
}

随机插入 (插入在目标节点前)

void Insert(SListNode** pplist, SLTDataType pos,SLTDataType x)
{
	SListNode* tmp = 0;
	SListNode* prev = NULL;
	SListNode* cur = *pplist;
	if (pos == (*pplist)->data)
	{
		PushFront(pplist, pos);
	}
	else
	{
		while (cur->data != pos)
		{
			prev = cur;
			cur = cur->next;
		}
		prev->next = BuyNode(x);
		prev->next->next = cur;
	}
}

打印整个链表 

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

修改节点

就是查找,找到了就改。

void Modify(SListNode** pplist, SLTDataType pos, SLTDataType x)
{
	SListNode* cur = *pplist;
	while (cur->data!=pos)
	{
		cur = cur->next;
	}
	cur->data = x;
}

总结 

介绍链表的概念、单链表节点的语法结构、链表节点的头插、尾插、头删、尾删、链表节点的随机插入与随机删除以及随机修改。

  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值