链表
与数组相似,链表也是一种线性
数据结构。这里有一个例子:
链表中的每个元素实际上是一个单独的对象,而所有对象都通过每个元素中的引用字段链接在一起。
链表有两种类型:单链表和双链表。上面给出的例子是一个单链表,这里有一个双链表的例子:
一 简介 - 单链表
单链表中的每个结点不仅包含值
,还包含链接到下一个结点的引用字段
。通过这种方式,单链表将所有结点按顺序组织起来。
1. 结点结构
在大多数情况下,我们将使用头结点(第一个结点)来表示整个列表。
// Definition for singly-linked list.
struct SinglyListNode {
int val;
SinglyListNode *next;
SinglyListNode(int x) : val(x), next(NULL) {
}
};
2. 操作
与数组不同,我们无法在常量时间内访问单链表中的随机元素。 如果我们想要获得第 i 个元素,我们必须从头结点逐个遍历。 我们按索引
来访问元素
平均要花费 O(N)
时间,其中 N 是链表的长度。
例如,在上面的示例中,头结点是 23。访问第 3 个结点的唯一方法是使用头结点中的“next”字段到达第 2 个结点(结点 6); 然后使用结点 6 的“next”字段,我们能够访问第 3 个结点。
你可能想知道为什么链表很有用,尽管它在通过索引访问数据时(与数组相比)具有如此糟糕的性能。 接下来,我们将介绍插入和删除操作,你将了解到链表的好处。
2.1 添加操作 - 单链表
如果我们想在给定的结点 prev
之后添加新值,我们应该:
- 使用给定值初始化新结点
cur;
- 将
cur
的“next”字段链接到 prev 的下一个结点next
; - 将
prev
中的“next”字段链接到cur
。
与数组不同,我们不需要将所有元素移动到插入元素之后。因此,您可以在 O(1)
时间复杂度中将新结点插入到链表中,这非常高效。
示例
让我们在第二个结点 6 之后插入一个新的值 9。
我们将