环形链表是另一种形式的链式存储结构。它的特点是链表中最后一个结点的指针域指向头结点,整个链表形成一个环。
由于环形链表的末尾节点指向头节点,因此,我们可以仅使用一个指针来存储链表地址,而不需要使用两个指针。
例如,在 React 中,useState
的 Hook 就是基于环形链表实现的。当有多个更新任务时,会有一个 queue.pending
指针来指向环形链表的末尾节点,如下所示。
通过这样的方式,我们可以通过末尾节点快速访问首节点
1
// 尾部节点
2
tail
=
queue.pending
3
// 首节点
4
head
=
queue.pending.next
代码如下
10
// 创建新节点
20
const
update
=
{
30
next:
null
,
40
action
: ()
=>
{}
50
}
60
70
// 将新节点添加到末尾
80
const
tail
=
queue.pending
// 尾部节点
90
const
head
=
queue.pending.next
// 首节点
10
11
// 将新节点添加到尾部
12
tail.next
=
update
13
update.next
=
head
14
queue.pending
=
update
图例演示如下
创建一个新节点
让老的尾部节点指向新节点
让新节点指向首节点
让 queue.pending
指向新节点
循环链表的遍历需要特殊处理一下,一不小心可能会陷入无限循环当中,因此,我们要巧妙的设计一个缓存指针,来记录当前遍历到的节点。如果该节点与循环开始的节点相同,则推出循环。
代码如下
1
let
current
=
queue.pending
2
3
while
(
true
) {
4
current
=
current.next
5
if
(current
===
queue.pending) {
6
break
7
}
8
}
如果我们已知链表的长度,也可以使用 for
循环来遍历链表。
1
for
(
let
i
=
0
; i
<
length; i
++
) {
2
current
=
current.next
3
}
给你一个链表的头节点 head
,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos
不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true
。 否则,返回 false
。
示例 1
1
输入:head
=
[
3
,
2
,
0
,
-
4
], pos
=
1
2
输出:
true
3
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2
1
输入:head
=
[
1
,
2
], pos
=
0
2
输出:
true
3
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3
1
输入:head
=
[
1
], pos
= -
1
2
输出:
false
3
解释:链表中没有环。