单链表的实现

这是C++算法基础-数据结构专栏的第十九篇文章,专栏详情请见此处


引入

从这篇博客开始,我们就要正式学习数据结构了。

Q:什么是数据结构呢?

A:数据结构是在计算机中存储、组织数据的方式。小到变量、数组,大到线段树、平衡树,都是数据结构。
Q:为什么要使用数据结构呢?

A:程序运行离不开数据结构,不同的数据结构又各有优劣,能够处理的问题各不相同,而根据具体问题选取合适的数据结构,可以大大提升程序的效率。所以,学习各种各样的数据结构是很有必要的。

而链表就是一种常见的数据结构,它分为单链表和双链表,它们的区别是指针的指向。

下面我们就来讲单链表的实现。

定义

链表是一种用于存储数据的数据结构,使数组如链条一般的方法连接元素。它的特点是插入与删除数据十分方便,但寻找与读取数据的表现欠佳。

单向链表中包含数据域和指针域,其中数据域用于存放数据,指针域用来连接当前结点和下一节点。它的主要用途是储存邻接表(树与图的一种存储方式)。

过程

Tips:操作链表时,每个节点的指向的部分比较抽象,光靠文字描述和代码可能难以理解,建议配合作图来理解。

链表的实现方式通常有两种,一种是结构体+指针,一种是定义多个数组实现,而比较容易理解和代码实现的则是第二种方法,所以我们这次就要讲解用数组实现的链表。

单链表的最主要操作有三个:构建、插入(写入)数据和删除数据

请注意:下面文字中"某一节点的下一个节点"和"某一节点++所存储++的下一个节点"是有区别的! "某一节点所存储的下一个节点"指的是这个节点的中存储的下标!

构建单链表

首先需要创建两个数组:存储每个节点的值存储每个节点的下一个节点的下标 ,这两个数组是用下标关联起来 的;再创建一个头结点 ,刚开始它指向空节点(-1 ),链表中有节点后就指向第一个节点;其次还需要一个变量,表示当前节点的下标

向链表中插入(写入)数据

需要说明一点:链表中每个节点的下标不需要管顺序,也就是说,下标位3的节点不一定就在下标为5的节点前面。

节点后插入一个节点的流程大致如下:

  1. 节点的中存储数值;
  2. 节点的存储为节点所存储的
  3. 节点的存储为

首先,图一展示了起始状态;然后,在新节点上面储存数据 (第一步,图二);由于新节点要插在节点后,所以新节点的下一个节点要赋值为节点所存储的下一个节点 (第二步,图三);最后,节点的下一个节点要赋值为节点(第三步,图四)。

还有一点需要注意,操作完成后需要,以便进行下一个节点的插入。

除了向节点后插入一个节点,也有向头节点后插入一个节点(简称头插)的操作,这两者虽然代码实现有所不同,但是思路大同小异,那头插的代码就不再展示了,留给读者去思考。(删除数据也有类似操作,后面也不再讲解)

Q:上文提到定义多个数组实现比较容易,它有什么优越性呢?

A:这种方式除了代码比较简短,容易理解,再就是插入(写入)数据(创建新节点)很快。

在链表中删除数据

节点后的节点删除,实际就是将节点的存储为它所存储的所存储的

首先,图一展示了起始状态;然后,节点的下一个节点要赋值为节点所存储的下一个节点所存储的下一个节点(第一步,图二)(这句话好像绕口令o((⊙﹏⊙))o)。

细心的人可能能发现,在图中下标为2的节点,经过删除操作后,已经没有用了,但是还是占用着内存,这样会不会有问题呢?

实际上,算法题目的内存限制很大,一般不需要管被删除的节点下标,在工程上我们才需要注意(这种情况是使用动态链表实现的,删除后就自动释放内存了)。

我们可以看出,虽然空间浪费了,但是时间复杂度比自动释放内存的动态链表要快,这种方法称为空间换时间

性质

这里,我们通过链表与数组之间的区别来理解链表的性质。

链表和数组都可用于存储数据。与链表不同,数组将所有元素按次序依次存储。不同的存储结构令它们有了不同的优势:

链表因其链状的结构,能方便地删除、插入数据 ,操作次数的时间复杂度是的。但也因为这样,寻找、读取数据的效率不如数组高 ,在访问数据中的时间复杂度是的。

数组可以方便地寻找并读取数据 ,在访问数据中的的时间复杂度是的。但删除、插入 的时间复杂度是的。

代码

下面给出单链表的实现代码:

int head,e[N],ne[N],idx;

void init(){
    head=-1;
    idx=0;
}

void add(int k,int x){
    e[idx]=x;
    ne[idx]=ne[k];
    ne[k]=idx++;
}

void remove(int k){
    ne[k]=ne[ne[k]];
}
代码解释

第一行的各种变量和数组已经在前面讲解了,这里不再详细讲解;init()函数的作用是初始化;add()函数的作用是将插到下标是的节点后面;remove()函数的作用是将下标是的节点后面的节点删掉。


上一篇- C++算法基础专栏文章 下一篇-


每周六更新一篇文章,内容一般是自己总结的经验或是在其他网站上整理的优质内容

点个赞,关注一下呗~

相关推荐
捕鲸叉5 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer5 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq5 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
wheeldown6 小时前
【数据结构】选择排序
数据结构·算法·排序算法
青花瓷7 小时前
C++__XCode工程中Debug版本库向Release版本库的切换
c++·xcode
幺零九零零8 小时前
【C++】socket套接字编程
linux·服务器·网络·c++
捕鲸叉8 小时前
MVC(Model-View-Controller)模式概述
开发语言·c++·设计模式
Dola_Pan9 小时前
C++算法和竞赛:哈希算法、动态规划DP算法、贪心算法、博弈算法
c++·算法·哈希算法
yanlou2339 小时前
KMP算法,next数组详解(c++)
开发语言·c++·kmp算法
小林熬夜学编程9 小时前
【Linux系统编程】第四十一弹---线程深度解析:从地址空间到多线程实践
linux·c语言·开发语言·c++·算法