let dist be a |V| × |V| array initialized to 0
for each vertex v
dist[v][v] ← 0
for each edge (u,v)
dist[u][v] ← 1 // u,v in order
for k from 1 to |V|
for i from 1 to |V|
for j from 1 to |V|
if dist[i][k] && dist[k][j] then
dist[i][j] // i,j in order
for i from 1 to |V|
if dist[i][i] // self circle
// circle detected
问题:如何检测一个链表是否有环,如果有,那么如何确定环的起点.
龟兔解法的基本思想可以用我们跑步的例子来解释,如果两个人同时出发,如果赛道有环,那么快的一方总能追上慢的一方。进一步想,追上时快的一方肯定比慢的一方多跑了几圈,即多跑的路的长度是圈的长度的倍数。
基于上面的想法,Floyd用两个指针,一个慢指针(龟)每次前进一步,快指针(兔)指针每次前进两步(两步或多步效果是等价的,只要一个比另一个快就行,从后面的讨论我们可以看出这一点)。如果两者在链表头以外的某一点相遇(即相等)了,那么说明链表有环,否则,如果(快指针)到达了链表的结尾,那么说明没环。
环的检测从上面的解释理解起来应该没有问题。接下来我们来看一下如何确定环的起点,这也是Floyd解法的第二部分。方法是将慢指针(或快指针)移到链表起点,两者同时移动,每次移动一步,那么两者相遇的地方就是环的起点。
Python:
def floyd(f, x0):
# The main phase of the algorithm, finding a repetition x_mu = x_2mu
# The hare moves twice as quickly as the tortoise
# Eventually they will both be inside the cycle
# and the distance between them will increase by 1 until
# it is divisible by the length of the cycle.
tortoise = f(x0) # f(x0) is the element/node next to x0.
hare = f(f(x0))
while tortoise != hare:
tortoise = f(tortoise)
hare = f(f(hare))
# at this point the position of tortoise which is the distance between
# hare and tortoise is divisible by the length of the cycle.
# so hare moving in circle and tortoise (set to x0) moving towards
# the circle will intersect at the beginning of the circle.
# Find the position of the first repetition of length mu
# The hare and tortoise move at the same speeds
mu = 0
tortoise = x0
while tortoise != hare:
tortoise = f(tortoise)
hare = f(hare)
mu += 1
# Find the length of the shortest cycle starting from x_mu
# The hare moves while the tortoise stays still
lam = 1
hare = f(tortoise)
while tortoise != hare:
hare = f(hare)
lam += 1
return lam, mu