正在载入交互式动画窗口请稍等
单链表-带头结点 可视化交互式动画版
在这篇文章中,我们将看到链表的介绍。
链表是一种线性数据结构,包含一系列相连的节点。 链表可以定义为随机存储在内存中的节点。 链表中的节点包含两部分,第一部分是数据部分,第二部分是地址部分。 列表的最后一个节点包含一个指向空值的指针。 链表是继数组之后第二常用的数据结构。 在链表中,每个链接都包含到另一个链接的连接。
链表的表示
链表可以表示为节点的连接,其中每个节点都指向链表的下一个节点。 链表的表示如下所示 -
到目前为止,我们一直使用数组数据结构来组织要单独存储在内存中的元素组。 然而,数组有几个优点和缺点,必须了解这些优点和缺点才能决定在整个程序中使用的数据结构。
现在,问题来了,为什么我们应该使用链表而不是数组?
为什么使用链表而不是数组?
链表是一种克服数组局限性的数据结构。 让我们首先看看数组的一些限制 -
- 在程序中使用数组之前必须事先知道数组的大小。
- 增加数组的大小是一个耗时的过程。 在运行时扩展数组的大小几乎是不可能的。
- 数组中的所有元素都需要连续存储在内存中。 在数组中插入一个元素需要移动其所有前驱元素。
链接列表很有用,因为 -
- 它动态分配内存。 链表的所有节点在内存中都是不连续存储的,并通过指针链接在一起。
- 在链表中,大小不再是问题,因为我们不需要在声明时定义其大小。 列表根据程序的需求而增长,并受到可用内存空间的限制。
如何声明一个链表?
数组的声明很简单,因为它是单一类型,而链表的声明比数组更典型一些。 链表包含两部分,两部分的类型不同,一是简单变量,二是指针变量。 我们可以使用用户定义的数据类型结构来声明链表 。
链表的声明如下 -
- 结构节点
- {
- 整数数据;
- 结构节点*下一个;
- }
在上面的声明中,我们定义了一个名为 node的 结构体,它包含两个变量,一个是整数类型的 数据 ,另一个是 next ,它是一个指针,包含下一个节点的地址。
现在,让我们转向链表的类型。
链表的类型
链表分为以下几种类型 -
- 单链表 - 单链表可以定义为有序元素集的集合。 单链表中的节点由两部分组成:数据部分和链接部分。 节点的数据部分存储该节点要表示的实际信息,而节点的链接部分存储其直接后继的地址。
- 双向链表 - 双向链表是一种复杂类型的链表,其中节点包含指向序列中前一个节点和下一个节点的指针。 因此,在双向链表中,一个节点由三部分组成:节点数据、指向序列中下一个节点的指针(next指针)、指向前一个节点的指针(previous指针)。
- 循环单链表 - 在循环单链表中,列表的最后一个节点包含指向列表的第一个节点的指针。 我们可以有循环单链表,也可以有循环双链表。
- 循环双向链表 - 循环双向链表是一种更复杂的数据结构类型,其中节点包含指向其前一个节点以及下一个节点的指针。 循环双向链表的任何节点中都不包含 NULL。 列表的最后一个节点包含列表的第一个节点的地址。 列表的第一个节点还包含其前一个指针中最后一个节点的地址。
现在,让我们看看使用链接列表的好处和局限性。
链表的优点
使用链表的优点如下:
- 动态数据结构—— 链表的大小可能根据需求而变化。 链表没有固定的大小。
- 插入和删除 - 与数组不同,链表中的插入和删除更容易。 数组元素存储在连续位置,而链表中的元素存储在随机位置。 要在数组中插入或删除元素,我们必须移动元素以创建空间。 而在链表中,我们不需要移位,只需更新节点指针的地址即可。
- 内存高效 - 链表的大小可以根据需要增长或缩小,因此链表中的内存消耗是高效的。
- 实现 - 我们可以使用链表来实现堆栈和队列。
链表的缺点
使用链表的限制如下:
- 内存使用 - 在链表中,节点比数组占用更多内存。 链表的每个节点占用两种类型的变量,一种是简单变量,另一种是指针变量。
- 遍历 - 在链表中遍历并不容易。 如果我们必须访问链表中的一个元素,我们不能随机访问它,而如果是数组,我们可以通过索引随机访问它。 例如,如果我们要访问第3个节点,那么我们需要遍历它之前的所有节点。 因此,访问特定节点所需的时间很大。
- 反向遍历 - 在链表中回溯或反向遍历是很困难的。 在双向链表中,它更容易,但需要更多内存来存储后向指针。
链表的应用
链表的应用如下:
- 借助链表,可以表示多项式,也可以对多项式进行运算。
- 可以使用链表来表示稀疏矩阵。
- 诸如学生详细信息、员工详细信息或产品详细信息之类的各种操作都可以使用链表来实现,因为链表使用可以容纳不同数据类型的结构数据类型。
- 使用链表,我们可以实现栈、队列、树等各种数据结构。
- 图是边和顶点的集合,图可以表示为邻接矩阵和邻接表。 如果我们想将图表示为邻接矩阵,那么可以将其实现为数组。 如果我们想将图表示为邻接表,那么可以将其实现为链表。
- 链表可以用来实现动态内存分配。 动态内存分配是在运行时完成的内存分配。
对链表执行的操作
列表支持的基本操作如下:
- 插入 - 执行此操作以将元素添加到列表中。
- 删除 - 执行从列表中删除操作。
- 显示 - 执行以显示列表的元素。
- 搜索 - 使用给定的键从列表中搜索元素。
链表的复杂性
现在,让我们看看链表的搜索、插入和删除操作的时间和空间复杂度。
1. 时间复杂度
运营 | 平均案例时间复杂度 | 最坏情况时间复杂度 |
---|---|---|
插入 | 复杂度(1) | 复杂度(1) |
删除 | 复杂度(1) | 复杂度(1) |
搜索 | 在) | 在) |
其中“n”是给定树中的节点数。
2. 空间复杂度
运营 | 空间复杂度 |
---|---|
插入 | 在) |
删除 | 在) |
搜索 | 在) |
链表的空间复杂度是 O(n)。
那么,链表的介绍就到此为止了。 希望这篇文章能给您带来帮助和信息。