我们学习另一种数据结构 —— 链表。

与数组相似,链表也是一种线性数据结构。这里有一个例子:
231123

正如我们所看到的,链表中的每个元素实际上是一个单独的对象,而所有对象都通过每个元素中的引用字段链接在一起。

链表有两种类型:单链表和双链表。上面给出的例子是一个单链表,这里有一个双链表的例子:
231123

温故而知新,学完这一模块,我们会:

1.了解单链表和双链表的结构;
2.在单链表或双链表中实现遍历、插入和删除;
3.分析在单链表或双链表中的各种操作的复杂度;
4.在链表中使用双指针技巧(快指针慢指针技巧);
5.解决一些经典问题,例如反转链表;
6.分析你设计的算法的复杂度;
7.积累设计和调试的经验。

- 单链表

单链表中的每个结点不仅包含值,还包含链接到下一个结点的引用字段。通过这种方式,单链表将所有结点按顺序组织起来。、

下面是一个单链表的例子:
231123
蓝色箭头显示单个链接列表中的结点是如何组合在一起的。
下面代码是单链表中结点的典型定义:

// Definition for singly-linked list.
public class SinglyListNode {
    int val;
    SinglyListNode next;
    SinglyListNode(int x) { val = x; }
}

与数组不同,我们无法在常量时间内访问单链表中的随机元素。 如果我们想要获得第 i 个元素,我们必须从头结点逐个遍历。 我们按索引来访问元素平均要花费 O(N) 时间,其中 N 是链表的长度。

例如,在上面的示例中,头结点是 23。访问第 3 个结点的唯一方法是使用头结点中的“next”字段到达第 2 个结点(结点 6); 然后使用结点 6 的“next”字段,我们能够访问第 3 个结点。

你可能想知道为什么链表很有用,尽管它在通过索引访问数据时(与数组相比)具有如此糟糕的性能。 在接下来的两篇文章中,我们将介绍插入和删除操作,你将了解到链表的好处。

之后,我们将为你提供练习设计自己的单链表。
如果我们想在给定的结点 prev 之后添加新值,我们应该:

1.使用给定值初始化新结点 cur;
231123

2.将 cur 的“next”字段链接到 prev 的下一个结点 next;
231123

3.将 prev 中的“next”字段链接到 cur 。
231123

与数组不同,我们不需要将所有元素移动到插入元素之后。因此,您可以在 O(1) 时间复杂度中将新结点插入到链表中,这非常高效。

示例

231123
让我们在第二个结点 6 之后插入一个新的值 9。

我们将首先初始化一个值为 9 的新结点。然后将结点 9 链接到结点 15。最后,将结点 6 链接到结点 9。

插入之后,我们的链表将如下所示:

231123

在开头添加结点

众所周知,我们使用头结点来代表整个列表。

因此,在列表开头添加新节点时更新头结点 head 至关重要。

初始化一个新结点 cur;
将新结点链接到我们的原始头结点 head。
将 cur 指定为 head。
例如,让我们在列表的开头添加一个新结点 9。

1.我们初始化一个新结点 9 并将其链接到当前头结点 23。

231123

2.指定结点 9 为新的头结点。
231123

posted on 2021-01-12 22:55  今今今生  阅读(74)  评论(0编辑  收藏  举报