链表
来源:互联网 发布:mac双系统默认windows 编辑:程序博客网 时间:2024/05/20 12:24
一.单链表的定义
线性表的链式存储又称为单链表,它是通过一组任意的存储单元来存储线性表中的数据元素。为了建立起数据元素之间的线性关系,对每个链表结点,除了存放元素自身的信息外,还需要存放一个指向其后继的指针。
单链表结点的结构如下图所示,其中,data为数据域,存放数据元素;next为指针域,存放其后继结点的地址。
对于每一个结点的描述如下:
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
利用单链表在解决顺序表需要大量的连续存储空间的缺点的同时,也引入了一些不可避免的缺点。比如因为需要额外的指针域,因此需要额外的存储空间;由于单链表是离散的分布在存储空间中,所以单链表不能完成随机存取的操作。
为了方便标识一个单链表,我们一般需要引入头指针来操作整个单链表。此外,为了统一增加和删除元素的操作,我们一般会在单链表的第一个结点之前附加一个结点,称为头结点。头结点的指针域指向单链表的第一个元素结点。
注:这里应该注意区分头指针和头结点。而不管单链表有没有头结点,头指针总是指向单链表的第一个结点。简单说就是如果单链表有头结点,那么头指针将指向头结点;如果单链表没有头结点,头指针将指向单链表的第一个结点。此处我们应该注意到一般情况下头结点内不存储任何信息。这里说明下,如果后面的例题中没有具体说明,一般都是建立有头结点的单链表。
引入头节点后,可以带来两个优点:
- 由于开始节点的位置被存放在头节点的指针域中,所以在链表的第一个位置上操作与表其他位置上的操作一致,无需进行特殊处理。
- 无论链表是否为空,其头指针都是指向头节点的非空指针(在空表中,头节点的指针域为空),因此也使得空表和非空表的处理方式变得统一。
二.单链表基本操作的实现
2.1建立单链表
2.1.1头插法建立单链表
该方法中,首先建立一个具有头结点的空单链表,然后每生成一个读取到数据的新节点,就将其放置到头结点之后。如下图所示:
算法描述如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
注:采用头插法建立单链表,读入数据的顺序与生成的链表中的元素的顺序刚好是相反的。
每个结点插入的时间复杂度为
2.1.2尾插法建立单链表
该方法中同样首先建立一个具有头结点的空单链表,然后每生成一个读取到数据的新节点,就将它插入到表尾;为了达到这样的目的,必须增加一个尾指针r,使其始终指向当前链表的尾结点。如下图所示
算法描述如下
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
注:因为附加设置了一个指向表尾的尾指针r,因此每个结点插入的时间复杂度同样为
2.2按序号查找结点值
从单链表的第一个结点出发,顺着指针next域逐个从上往下搜索,直到找到第i个结点为止,否则返回最后一个结点指针域NULL。
算法描述如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
注:按序号查找的时间复杂度为
2.3按值查找结点值
从单链表的第一个结点开始,由前往后依次比较各结点数据域的值,若某结点数据域的值等于给定值x,则返回该结点的指针。若整个单链表中没有这样的结点,则返回NULL。
算法描述如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
注:按值查找的时间复杂度为
2.4插入结点
2.4.1插入后继结点
插入操作是将值为x的新结点插入倒单链表的第
算法首先需要调用GetElem(L,i-1)
查找第
算法描述如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
算法中,时间的主要开销是查找第
2.4.1插入前驱结点
在方法一中,我们可以在指针p指向的结点后面插入新的结点s,但是有时如果我们需要在指针p指向的结点前面插入新的结点s时,上述算法明显是办不到的。
但是如果我们换个思路,将指针p指向的结点和s结点它们之间的数据域做一次交换,依旧将s结点插入到指针p指向的结点后面,如此我们便将前插操作变为了向指针p指向的结点的后插操作,并且在逻辑上仍旧满足条件。
算法描述如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
注:同方法一相同,时间的主要开销是查找第
2.5删除结点
2.5.1删除后继结点
删除结点操作即将单链表的第
假设我们要删除指针q指向的结点,那么我们首先通过遍历所有结点找到指针q指向的结点的前驱结点p,为了实现算法,我们只需修改指针p的指针域,将指针p的指针域next直接指向指针q指向的结点的指针域next所指的下一个结点便可。
算法描述如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
注:删除操作中,时间的主要开销是查找第
2.5.2删除自身结点
有时我们需要删除指针所指向的自身结点(比如指针p指向的结点),此时如果继续使用上述方法明显是不可能的。我们采用与2.4.1插入前驱结点
相似的方法,将指针p所指向的结点的数据域与指针q所指向的结点的数据域进行一次交换(因为是一次删除操作,我们只需要将指针q指向的结点的数据域直接赋值为指针p指向的结点的数据域便可),这样,我们就又变成了删除指针q指向的结点的操作。
算法描述如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
注:与上述算法一样,删除操作中,时间的主要开销是查找第
2.5求链表长度
求表长实际上就是计算单链表中数据结点(不含头节点)的个数。为了达到这个目的,我们只需对链表进行一次遍历,同时设置计数器对每次访问到的结点计数便可。
算法描述如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
注:遍历操作中需要访问所有结点,因此时间复杂度为
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- Python-webdriver 怎么定位下拉列表中的元素呢
- JavaScript中call,apply,bind方法的总结
- 多态
- webshell网络资料整理
- Unity 2017引入的新图集方式
- 链表
- eclipse 中使用maven
- grails domain 如何不生成对应的表、如何不生成某些字段的表字段等
- linux下MongoDB安装
- Android下pm 命令详解
- 一个内存空洞问题的定位
- Wdcp_V3下配置ssl证书(web引擎版本:nginx+apache)教程
- 数组,list<T>,arraylist
- RxJava的使用(一)