摘要:带头双向循环链表结构最复杂,一般用在多带带存储数据。实际中使用的链表数据结构,都是带头双向循环链表。
目录
注意:
1.众上图可看出,链式结构在逻辑上是连续的,但是在物理上不一定连续
2.现实中的结点一般都是从堆上申请出来的
3.从堆上申请的空间,是按照一定的策略来分配的,两次申请的空间可能连续,也可能不连续
假设在32位系统上,结点中值域为int类型,则一个节点的大小为8个字节,则也可能有下述链表:
1. 无头单向非循环链表:结构简单,一般不会多带带用来存数据。实际中更多是作为其他数据结构的子结 构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
2. 带头双向循环链表:结构最复杂,一般用在多带带存储数据。实际中使用的链表数据结构,都是带头双向 循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而 简单了,后面我们代码实现了就知道了。
//定义单链表typedef int SLTDataType;//方便修改存储数据类型typedef struct SlistNode//节点{ SLTDataType data;//数据域 struct SlistNode* next;//指针域}SLTNode;//结构名改短一点
//单链表的空间开辟SLTNode* BuySLTNode(SLTDataType el){ SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode)); //开辟新节点,判断是否错误 if (newnode == NULL) { perror("错误原因"); exit(-1); } //给新节点的数据域和指针域分别赋值 newnode->data = el; newnode->next = NULL; return newnode;}
//单链表的尾插void SListPushBack(SLTNode** pphead, SLTDataType el){ //0节点 assert(pphead); if (*pphead == NULL) { *pphead = BuySLTNode(el); } else { //找到尾结点 SLTNode* tail = *pphead; while (tail->next != NULL) { tail = tail->next; } //到尾了,开辟空间 SLTNode* newnode = BuySLTNode(el); //连接 tail->next = newnode; }}
1.找到尾结点
2.到尾了,开辟空间
3.连接新开辟的空间
//单链表的头插void SListPushFront(SLTNode** pphead, SLTDataType el){ assert(pphead);//0节点 //创建新节点 SLTNode* newnode = BuySLTNode(el); //新节点连接原来的头结点 newnode->next = *pphead; //*pphead指向新节点 *pphead = newnode;}
1.创建新节点
2.新节点连接原来的头结点
3.*pphead指向新节点
//单链表的数据打印--for遍历void SListPrint(SLTNode* phead){ SLTNode* cur = phead; while (cur) { printf("%d->",cur->data); cur = cur->next; } printf("NULL/n");}
//单链表的尾删void SListPopBack(SLTNode** pphead){ assert(pphead);//0节点 // 温柔的一点 /*if (*pphead == NULL) { return; }*/ // 粗暴一点 assert(*pphead);//1节点 //两种情况: //1个节点 //2个节点以上 if ((*pphead)->next == NULL)//只有一个节点时 { free(*pphead); *pphead = NULL; return; } //多节点时 找倒数第二个节点 SLTNode* cur = *pphead; while (cur->next->next != NULL) { cur = cur->next; } //free去掉最后一个节点 free(cur->next); //置NULL cur->next = NULL;}
2种情况
一个节点时,释放且置空
多节点时:
1.找倒数第二个节点
2.free最后一个节点
3.置空
单链表头删
//单链表的头删void SListPopFront(SLTNode** pphead){ assert(*pphead);//0节点 assert(*pphead);//1节点 SLTNode* next = (*pphead)->next;//记住第二个节点地址 free(*pphead);//释放第一个节点 *pphead = next;//连接第二个节点}
1.记住第二个节点地址
2.释放第一个节点
3.链接第二个节点
//单链表的值查找操作SLTNode* SListFind(SLTNode* phead, SLTDataType el){ SLTNode* cur = phead; while (cur) { if (cur->data == el) { return cur; } else { cur = cur->next; } } return NULL;}
//单链表在pos位置删除void SListErase(SLTNode** pphead, SLTNode* pos){ assert(pphead);//0节点情况 assert(pos);//防止向空链表删除//1个节点直接头删 if (*pphead == pos) { /*pphead=pos->next; free(pos);*/ SlistPopFront(pphead); }//多个节点时 else { SLTNode* prev = *pphead; while (prev->next != pos)//找到pos前位置 { prev = prev->next; } prev->next = pos->next;//链接目标节点前后 free(pos);//销毁目标节点 }}
1个节点:直接头删
多个节点:
1.找到pos位置
2.链接目标节点前后位置
3.销毁目标节点
单链表pos位置删除图片
//单链表在pos位置前插入void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x){ assert(pphead);//防止空节点情况 assert(pos);//防止向空链表插入 SLTNode* newnode = BuylistNode(x); //一个节点,头插 if (*pphead == pos) { newnode->next = *pphead; *pphead = newnode; } //多个节点 else { //找到pos的前一个位置 SLTNode* posPrev = *pphead; while (posPrev->next != pos) { posPrev = posPrev->next; } //链接 posPrev->next = newnode; newnode->next = pos; }}
一个节点:头插
多个节点:找到pos前位置,进行链接
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/123295.html
单链表的基本操作【超详细备注和解释】 先赞后看好习惯 打字不容易,这都是很用心做的,希望得到支持你 大家的点赞和支持对于我来说是一种非常重要的动力 看完之后别忘记关注我哦!️️️ 强烈建议本篇收藏后再食用 文章目录 单链表基本介绍基本结构与顺序表的区别以及学习单链表的必要性 单链表的实现结点的定义以及头指针的创建单链表的遍历(打印接口的实现)【重点】开辟结点接口尾插接口尾删接口头插接口...
摘要:概述前面的文章说到了一种很基础的数据结构链表数据结构与算法链表,今天就来看看关于单链表的几种常见的操作,技术笔试的时候很大概率能够遇到其中的一些。 1. 概述 前面的文章说到了一种很基础的数据结构——链表:数据结构与算法——链表,今天就来看看关于单链表的几种常见的操作,技术笔试的时候很大概率能够遇到其中的一些。多练习一下,对我们理解链表有很大的帮助,也能够提升我们的编码能力。废话不多说...
摘要:实际中更多是作为其他数据结构的子结构,如哈希桶图的邻接表等等。单链表的结构头节点数据节点三单链表的实现光说不练假把式,我们了解了链表的结构用处。对于无头单向链表。 ...
摘要:实际中更多是作为其他数据结构的子结构,如哈希桶图的邻接表等等。单链表的结构头节点数据节点三单链表的实现光说不练假把式,我们了解了链表的结构用处。对于无头单向链表。 ...
阅读 3114·2021-11-24 09:39
阅读 3599·2021-11-22 09:34
阅读 983·2021-11-15 11:38
阅读 1613·2021-10-11 10:58
阅读 3635·2021-10-08 10:04
阅读 4518·2021-08-11 11:17
阅读 954·2019-08-29 13:58
阅读 2426·2019-08-28 18:18