带你深度——了解《链表》(C实现)①

目录

一.✨链表的概念及结构

二.✨链表的分类

三.✨单链表的实现

  1.🎈动态申请一个节点

2.🎈单链表的尾插

3.🎈单链表的尾删

4.🎈单链表的头插

5.🎈单链表的头删

6.🎈单链表的查找

7.🎈单链表的pos位置之后插入

8.🎈单链表的销毁

四.✨总结


一.✨链表的概念及结构


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

   

现实中,数据结构中

注意:

1.从上图可以看出,链式结构在逻辑上是连续,的但是在物理上不一定连续 。

2.现实中的节点一般都是从堆上申请出来的

3.从堆上申请的空间,是按照一定策略来分配的,俩次申请的空间可能连续,也可能不连续

二.链表的分类

        🎈实际中链表的结构非常多样

         1.🎈 带头的或者不带头的

         2.🎈循环的或者不循环的 

         3,🎈单向的或者双向的   等等等等

而今天我们主要讲的就是单链表和带头循环链表

1. 🎈无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。


2. 🎈带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了,后面我们代码实现了就知道了  
 

三.✨单链表的实现

       🎈单链表的结构,一个单元存储数据,一个单元存储下一个数据的地址;

typedef int SLTDateType;
typedef struct SListNode
{
	SLTDateType data;
	struct SListNode* next;
}SListNode;

  1.🎈动态申请一个节点

   单链表的插入,首先要先创建一个节点,我们用malloc来创建一个数据

SListNode* BuySListNode(SLTDateType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));

	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}

	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

2.🎈单链表的尾插

    单链表的尾部插入,首先动态申请一个新节点,然后判断链表,是否为空,为空直接赋值给链表,如果不为空,找到链表的尾部 然后进行插入。

void SListPushBack(SListNode** pplist, SLTDateType x)
{
	SListNode* newnode = BuySListNode(x);

	if (*pplist == NULL)
	{
		*pplist = newnode;
	}
	else
	{
		SListNode* tail = *pplist;
		// 找尾
		while (tail->next)
		{
			tail = tail->next;
		}

		tail->next = newnode;
	}
}

3.🎈单链表的尾删

void SListPopBack(SListNode** pplist)
{
	//断言  链表为空
	assert(*pplist);

	//链表就一个元素
	if ((*pplist)->next == NULL)
	{
		free(*pplist);
		*pplist = NULL;
	}
	else  //链表为多元素
	{
		SListNode* tail = *pplist;
		while (tail->next->next)//找到倒数第二个元素
		{
			tail =  tail->next;//最后tail  指向的是倒数第二个元素
		}
		free(tail->next);//释放掉最后一个
		tail->next = NULL;//倒数第二个元素变为最后一个  置为空
	}
}

4.🎈单链表的头插

      看到这个代码是不是很惊喜  这就是单链表的头插 ,也是单链表的优势所在,相较于顺序表的头插,单链表的头插十分的方便,申请节点之后 把节点指向头节点,然后再把头节点变为新申请的节点。

void SListPushFront(SListNode** pplist, SLTDateType x)
{
	SListNode* newnode = BuySListNode(x);
	newnode->next = *pplist;  //new 链接 pp
	*pplist = newnode;  
}

5.🎈单链表的头删

         头删相较于头插一样,也是十分的方便的,先保存头部指向的下一处地址,然后删除头部,把头部置成头部下一处地址处就好了。

void SListPopFront(SListNode** pplist)
{
	SListNode* next = (*pplist)->next;//next  指向 头部的下一个地址
	free(*pplist);//删除头部
	*pplist = next;//头部指向下一个地址处·
}

6.🎈单链表的查找

SListNode* SListFind(SListNode* plist, SLTDateType x)
{
	SListNode* sur = plist;

	while (sur)
	{
		if (sur->data == x)
		{
			return sur;
		}
		sur = sur->next;
	}
	return NULL;  
}

7.🎈单链表的pos位置之后插入

void SListInsertAfter(SListNode* pos, SLTDateType x)
{
	assert(pos);

	SListNode* cur = BuySListNode(x); //先动态申请一个节点
	
	 cur->next = pos->next;//先把后面的节点给新节点
	 pos->next = cur;//再把pos的下一个节点指向cur
}

8.🎈单链表的销毁

void SListDestroy(SListNode** plist)
{
	SListNode* cur = *plist;
	while (cur)
	{
		SListNode* newnode = cur->next;//新节点等于初始下一个

		free(cur);   //删除头
	
		cur = newnode;// 头等于新节点

	}
	*plist = NULL;
}

四.✨总结

      想一想为什么单链表的pos位置插入 为什么不在之前插入呢???

      由上表查看,单链表的优势是头插头删,

      但是单链表要是想像顺序表一样随机访问存储确实不行的

      下一期 ,我们在一起探讨了解 带头双向循环链表,是不是听名字就很炫酷呢!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值