欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > DS线性表之单链表的讲解和实现(2)

DS线性表之单链表的讲解和实现(2)

2024/10/26 0:22:04 来源:https://blog.csdn.net/2301_80392199/article/details/142881645  浏览:    关键词:DS线性表之单链表的讲解和实现(2)

文章目录

  • 前言
  • 一、链表的概念
  • 二、链表的分类
  • 三、链表的结构
  • 四、前置知识准备
  • 五、单链表的模拟实现
    • 定义头节点
    • 初始化单链表
    • 销毁单链表
    • 打印单链表
    • 申请节点
    • 头插数据
    • 尾插数据
    • 头删数据
    • 尾删数据
    • 查询数据
    • 在pos位置之后插入数据
    • 删除pos位置之后的数据
  • 总结


前言

  本篇的单链表完全来说是单向不带头单链表,这种和另外一种链表(双向带头循环链表)使用最广泛,我们只要对它们两个有所了解即可

  正文开始!


一、链表的概念

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

二、链表的分类

在这里插入图片描述

三、链表的结构

  就如同下图一样,一节一节,前面连着后面就是链表的一种表现
在这里插入图片描述
在这里插入图片描述
同时我们也发现以下几点:

  1. 从上图可看出,链式结构在逻辑上是连续的,但是在物理上不一定连续
  2. 节点一般都是在上申请出来的
  3. 从堆上申请空间,两次申请得到的内存可能连续,也可能不连续

物理结构:数据实际存储在内存中的结构;
逻辑结构:想象出来的结构

四、前置知识准备

在正式开始实现之前,我希望你有以下认识:

  1. 实现部分接口需要通过二级指针接受实参:原因在于我们需要可以修改实参(而形参只是实参的一份拷贝,要想修改实参,必须得传指针,同样若实参本来就是指针,那么就要传指针的指针,即二级指针),而是实参为一级指针时(同样是传递地址),需要使用二级指针进行接受,否则获得临时拷贝,不会影响到实参。修改实参的情况,比如一开始为空,在插入时需将头指针存储在有效结点的的地址上,需要改变实参的值
  2. 单链表的初始化:这里实现链表,没有必要进行初始化,初始化对于一开始就要开辟的空间有初始化的需求,表示多个节点通过地址链接在一起,那么只需要开辟新节点的时候,初始化下就行了(有哨兵位需要初始化)
  3. 二级指针断言:二级指针存放的是头节点的地址,头节点的地址为空,那么还有什么意义呢?

五、单链表的模拟实现

定义头节点

//单链表节点
//根据定义需要存储一个数据和一个指向下一个结点的指针
typedef int SLDataType;//定义数据类型,可以根据需要更改,typedef一下就很方便
typedef struct SList
{SLDataType data;    //数据域 存储数据struct SList* next; //指针域 存储指向下一个结点的指针
}SList;

请注意,这里不能在节点内就单独用SList来定义next指针,因为这时候还没有typedef成功呢,还在节点内部

初始化单链表

因为创建一个变量实质是给变量开辟一块内存空间,但是这块内存空间可能有遗留的数据,所以在创建变量之后需要进行初始化,而数据域我们也不清楚到底该传那个,随便传个0就行,但是指针域就必须置空了,否则就是野指针

void SListInit(SList* phead)
{assert(phead);     //防止传入空指针,传入则报错phead->data = 0;   //将数据初始化为0phead->next = NULL;//将结点指针初始化为NULL
}

销毁单链表

有开辟内存,自然而然的就有还回内存,即销毁单链表

在这里插入图片描述

void SListDestroy(SList* phead)
{assert(phead);SList* cur = phead; //为了能在后序找到头结点,所以新创建一个变量指向头结点while (cur != NULL){SList* next = cur->next;free(cur);cur = next;}
}

我们不妨来想想为什么是传一级指针即可,首先,我们这里是为了销毁内存,虽然说形参的这个节点指针和实参的节点指针地址不一样,但是所存的节点都是同一个节点!,所以可以直接传指针,有因为我们说链表在物理上是不连续的,所以得通过指针跳着跳着一个个销毁

打印单链表

在这里插入图片描述
同样的,我们只要传一级指针就可以了,且通过指针来跳转

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

申请节点

在插入中使用相当频繁,所以我们再对此单独实现一个函数,使得代码更加的结构化
在这里插入图片描述
请注意,指针并不单独开空间,它起到的更多是一个中间人的作用,通过指针来控制

SList* BuySeqList(SLDataType x)
{SList* pnewNode = (SList*)malloc(sizeof(SList));//动态开辟一个单链表类型大小if (pnewNode == NULL)//动态开辟的内存不一定成功,所以需要判断{printf("malloc fail\n");exit(-1);}//内存开辟成功则把数据赋值到指定位置pnewNode->data = x;pnewNode->next = NULL;return newnode;
}

头插数据

在这里插入图片描述

void SListPushFront(SList** pphead, SLDataType x)
{SList* newnode = BuySeqList(x);newnode->next = *pphead;*pphead = newnode;
}

尾插数据

在这里插入图片描述

void SListPushBack(SList** pphead, SLDataType x)
{SList* newnode = BuySeqList(x);if (*pphead == NULL) // 没有节点的时候{*pphead = newnode;}else // 有节点的时候{SList* tail = *pphead;while (tail->next != NULL){tail = tail->next;}tail->next = newnode;}
}

头删数据

void SListPopFront(SList** pphead)
{assert(*pphead);//头结点不为空则有数据SList* head = (*pphead)->next;free(*pphead);*pphead = head;
}

在这里插入图片描述

尾删数据

void SListPopBack(SList** pphead)
{assert(*pphead);if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SList* tail = *pphead;SList* prev = NULL;while (tail->next != NULL){prev = tail;tail = tail->next;}free(tail);tail = NULL;prev->next = NULL;}
}

在这里插入图片描述

查询数据

找到则返回当前当前数据结点地址,没找到则返回空地址
在这里插入图片描述

SList* SListFind(SList* phead, SLDataType x)
{assert(phead);SList* cur = phead;while (cur != NULL){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}

在pos位置之后插入数据

在这里插入图片描述

void SListInsertAfter(SList* pos, SLDataType x)
{assert(pos);SList* newnode = BuySeqList(x);SList* next = pos->next;pos->next = newnode;newnode->next = next;
}

删除pos位置之后的数据

在这里插入图片描述

void SListEraseAfter(SList* pos)
{assert(pos);assert(pos->next);//判断pos之后是否有数据,没数据则报错SList* next = pos->next->next;free(pos->next);pos->next = next;
}

总结

  链表可以说是CS学生遇到的第二个劝退点了(第一个是指针),它是我们所学知识的一个集成展现,需要我们对前面知识的充分掌握,所以对计算机来说,知识比较连贯,这也是学习它比较难受的地方

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com