![7870625c9e65d50225001f8f199b44f0.png](https://i-blog.csdnimg.cn/blog_migrate/0419f3c80ca12b6d0a08a42d4f00fd45.png)
前几天我们开了个数据结构的坑,说了栈,留言里有同学提到链表,那今天码哥就来讲讲链表。
链表是什么
链表、列表,说起来有点相似,作用也有点类似,但可别傻傻分不清楚。我们一般说的列表,是一个连续的序列,用来存储一组数据。而链表,虽然也是有序的存储结构,但它不限定要“连续”的。
打个比方:列表就好像火车,每一节车厢连在一起,如果你知道车头在哪里,大致就也能知道第8节车厢在哪。
而链表,就像是去往同个目的地的车队,有很多辆车,大家排着队行驶。虽是一个整体,但队伍的顺序是可以很容易调整的。
![c9920f850f91093cd7ed0b994cf296da.png](https://i-blog.csdnimg.cn/blog_migrate/4dfd223c51509e94bdb2466bc9955ca2.jpeg)
从概念定义上来说,链表是一种以线性顺序存储的数据结构,但并不要求按顺序存储。它由节点组成,每个节点除了储存自身数据外,还包含一个指向下一个节点的引用(或指针)。
这就是一个包含5个节点的链表示意图:
![93e551a2373cf85aef2a4cd652a9deda.png](https://i-blog.csdnimg.cn/blog_migrate/1729a54c169fe3a7306e8dae864a0c30.jpeg)
通常,我们会有一个 head 引用指向链表的开头,而链表的结尾,下一个节点则指向空值 None。
除了上图演示的单向链表外,还存在双向链表(每个节点还增加一个指向前一个节点的引用)和循环链表(最后一个节点的下一个节点会指向第一个节点)。
链表有什么用
老问题又来了:为什么要有链表?
链表相较顺序存储列表,最大的好处就是很容易往序列中添加和删除元素,单看插入和删除操作,最优可达到O(1)的复杂度。这个从上面举的火车和车队的例子就可以想象出来。另外,链表的好处还有不需要连续的存储空间,且不需要预先知道数据集的大小。
但链表也有它的不足,就是如果你要查找某个节点,或访问指定序号的节点,效率则比较低。
所以,链表更适合需要频繁增删元素但很少查找元素,或者无法预知数据规模的场景。
举一个例子:玩过格斗游戏的人,都知道有个“搓招”的设定,就是你按下一定顺序的按键(如 →↓↘→AB),就会触发角色的特殊招式。当玩家操作角色时,会不停按下各个按键,这时如果你想判断最近的按键组合是否符合某一固定招式,就可以用链表来记录最近的按键历史,并且在过程中不断更新。
![69c1de78387d5a4f785d563cd2c04ca3.gif](https://i-blog.csdnimg.cn/blog_migrate/7b8004fc5a5a746f92a4a960be880f7c.gif)
那么,为何我们标题说链表是数据结构的重要根基呢?因为从上面的描述我们可以看出,链表的节点是非常灵活的,可以组织成不同的结构。例如我们上次提到的栈,就完全可以改为用链表实现。其他的一些数据结构,如队列、树、图,一些算法,如 LRU(最近最少使用算法),文件系统等,均会用到链表这种数据结构。
最近又火起来的概念:区块链,它也是某种意义上的链表。
链表的实现
我们用 Python 语言来自己实现一个单向链表结构,以加深理解。
功能需求:
创建一个 SingleLinkedList 类,具备以下功能:
- SingleLinkedList() - 创建新的单链表,不需要参数,返回空链表。
- addFirst(item) - 将元素添加到链表头,需要参数,无返回值。
- remove(item) - 删除链表内元素,需要参数,并修改单链表的内容。
- isEmpty() - 检查单链表是否为空,不需要参数,返回布尔值。
- length() - 返回单链表中元素个数,不需要参数,返回整数。
开发思路:
照例先来几张示意图,理一下上述几个功能:
1. 创建节点、单链表并 addFirst(item)
![ee99b900fb7e81105f27c7b38313ffd9.png](https://i-blog.csdnimg.cn/blog_migrate/1c60bc820e55abbe9d7ef522dee18bc8.jpeg)
2. 继续 addFirst(item) 添加节点。
![c3729d568b2920aa5b1a9277d3310998.png](https://i-blog.csdnimg.cn/blog_migrate/95716ac660d952a77ebb053191d0527b.jpeg)
3. 多次添加节点后就会出现我们开头的单链表。
![f51f0ca16c4393b5953574c44603e71b.png](https://i-blog.csdnimg.cn/blog_migrate/0d5963dc96dab2fb57977a97f31b41b8.jpeg)
![93e551a2373cf85aef2a4cd652a9deda.png](https://i-blog.csdnimg.cn/blog_migrate/1729a54c169fe3a7306e8dae864a0c30.jpeg)
4. 删除储存数据为4的头部节点
![3631293f041e1d4d29f83cce6f228707.png](https://i-blog.csdnimg.cn/blog_migrate/a3867e1d5d25d8ace04045d8aa2d056b.jpeg)
5. 删除链表中间储存元素为2的中间节点
![07a6f57a441d0140f15f21d50594c026.png](https://i-blog.csdnimg.cn/blog_migrate/a66313f2583a3d844ea78e7862b2847e.jpeg)
在删除链表元素的过程包含两个步骤:
1. 遍历链表,找到删除的元素。我们从 head 节点找起,直到 next 节点为 None 的尾部节点
2. 当找到元素后,将其前一个节点的 next 节点指向它原本的 next 节点,也就实现了从列表中删除元素
代码实现:
class
以上便是一个单链表的 Python 实现。
觉得码哥说得还行,还望动动手指点个“赞同”支持一下。也欢迎大家来关注我的“编程学习者社区”,我们一起学编程!
作者:码不理
来源:编程学习者社区