定义
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。
每个结点包括两个部分:一个是存储数据元素的数据域(设域名为data),另一个是存储下一个结点地址的指针域(设域名为next)。指针域中存储的信息又称做指针或链。
复杂度比较
| 链式结构 | 顺序结构 | |
|---|---|---|
| 插入 | O(1) | O(n) |
| 查找一个节点 | O(n) | O(logn) |
| 访问特定编号的节点 | O(n) | O(1) |
链表特点
- 链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。
- 链表存储单元可以是连续的,也可以是不连续的。
- 链表增加了结点的指针域,空间开销比较大。
- 链表允许插入和移除表上任意位置上的节点。
- 链表不允许随机存取。
- 链表查找一个数,必须要从头开始找起。
类别
- 单向链表
- 双向链表
- 循环链表
- 块状链表
存储结构
链表中的节点不需要以特定的方式存储,但是集中存储也是可以的,主要分下面这几种具体的存储方法:
- 共享存储空间
链表的节点和其它的数据共享存储空间,优点是可以存储无限多的内容(不过要处理器支持这个大小,并且存储空间足够的情况下),不需要提前分配内存;缺点是由于内容分散,有时候可能不方便调试。 - 独立存储空间
一个链表或者多个链表使用独立的存储空间,一般用数组或者类似结构实现,优点是可以自动获得一个附加数据:唯一的编号,并且方便调试;缺点是不能动态的分配内存。当然,另外的在上面加一层块状链表用来分配内存也是可以的,这样就解决了这个问题。这种方法有时候被叫做数组模拟链表,但是事实上只是用表示在数组中的位置的下标索引代替了指向内存地址的指针,这种下标索引其实也是逻辑上的指针,整个结构还是链表,并不算是被模拟的(但是可以说成是用数组实现的链表)。
链表的应用
链表用来构建许多其它数据结构,如堆栈,队列和他们的派生。
节点的数据域也可以成为另一个链表:
- 用列表来构建许多链性数据结构
- 链表用来生成联合数组(联合数列)
单向链表
单向链表(单链表)是链表的一种,它由节点组成,每个节点都包含下一个节点的指针。 一个单向链表的节点被分成两个部分:第一个部分保存或者显示关于节点的信息,第二个部分存储下一个节点的地址。
单链表的特点是:节点的链接方向是单向的;相对于数组来说,单链表的的随机访问速度较慢,但是单链表删除/添加数据的效率很高。
单链表删除节点
单链表添加节点
双向链表
双向链表(双链表)是链表的一种。和单链表一样,双链表也是由节点组成,它的每个数据结点中都有两个指针,分别指向直接后继(当此“连接”为最后一个“连接”时,指向空值或者空列表)和直接前驱(当此“连接”为第一个“连接”时,指向空值或者空列表)。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。
一般是在需要大批量的另外储存数据在链表中的位置的时候用。
由于另外储存了指向链表内容的指针,并且可能会修改相邻的节点,有的时候第一个节点可能会被删除或者在之前添加一个新的节点。这时候就要修改指向首个节点的指针。有一种方便的可以消除这种特殊情况的方法是在最后一个节点之后、第一个节点之前储存一个永远不会被删除或者移动的虚拟节点,形成一个循环链表。
循环链表
循环链表是一种链式存储结构,它的最后一个结点指向头结点,形成一个环。因此,从循环链表中的任何一个结点出发都能找到任何其他结点。
双向循环链表
一般我们都构造双向循环链表。
双向循环链表删除节点
双向循环链表添加节点
块状链表
块状链表本身是一个链表,但是链表储存的并不是一般的数据,而是由这些数据组成的顺序表。每一个块状链表的节点,也就是顺序表,可以被叫做一个块。
块状链表通过使用可变的顺序表的长度和特殊的插入、删除方式,可以在达到的复杂度。块状链表另一个特点是相对于普通链表来说节省内存,因为不用保存指向每一个数据节点的指针。