使用Hare和Tortoise方法在链表中进行循环检测

时间:2011-06-26 08:12:44

标签: algorithm linked-list detection cycle floyd-cycle-finding

据我所知,为了检测链表中的循环,我可以使用Hare和Tortoise方法,该方法包含2个指针(慢速和快速指针)。但是,在阅读了wiki和其他资源之后,我不明白为什么这两个指针会在O(n)时间复杂度上得到满足。

3 个答案:

答案 0 :(得分:30)

这是一次非正式证明的尝试。

周期的形状无关紧要。它可以有一个长尾巴,一个朝向末端的循环,或者只是一个从开始到结束而没有尾巴的循环。无论循环的形状如何,有一件事是清楚的 - 乌龟指针无法赶上野兔指针。如果两人永远相遇,野兔指针必须从后面赶上乌龟指针。

有了这个,考虑两个可能性:

  1. 野兔指针是乌龟指针背后的一步。
  2. 野兔指针是乌龟指针背后的两步。
  3. 所有更远的距离最终会减少到一两个。

    假设乌龟指针始终先移动(也可能是另一种方式),那么在第一种情况下,乌龟指针向前迈出一步。现在它们之间的距离是2.当野兔指针现在采取两步时,它们将落在同一节点上。这是为了便于理解而说明的相同内容。太多的文字可能会妨碍你。

    ♛ = hare
    ♙ = tortoise
    X = both meet
    
    ..♛♙... #1 - Initially, the hare is one step behind the tortoise.
    ..♛.♙.. #2 - Now the tortoise takes one step. now hare is two steps behind.
    ....X.. #3 - Next, the hare takes two steps and they meet!
    

    现在让我们考虑第二种情况,它们之间的距离是2.慢速指针向前移动一步,它们之间的距离变为3.接下来,快速指针向前移动两步,它们之间的距离减小到1与我们已经证明他们将再一次见面的第一个案例相同。再次,说明以便于理解。

    .♛.♙... #1 - Initially, the hare is two steps behind the tortoise.
    .♛..♙.. #2 - Now the tortoise takes one step and they become three steps apart.
    ...♛♙.. #3 - Next, the hare takes two steps which is identical to previous case.
    

    现在,至于为什么这个算法保证在O(n)中,使用我们已经确定的野兔在它前进之前遇到乌龟。这意味着一旦两者都在环路内,在乌龟完成另一轮之前,它将满足野兔,因为野兔的移动速度是原来的两倍。在最坏的情况下,循环将是一个具有n个节点的圆。虽然乌龟只能在n个步骤中完成一轮,但野兔在那段时间内可以完成两轮。即使野兔在第一轮中错过了乌龟(它将会),它肯定会在第二轮中赶上乌龟。

答案 1 :(得分:3)

让迭代器AB分别按1和2进行列表。 Consdier存在一个循环。然后,当A进入循环时,B已经位于其中的某个位置。如果循环的长度为K,那么B将在]K/2[次移动中围绕它运行,因此最多在2*]K/2[次迭代中我们会遇到{{1}的情况} B位于A1: B->A的{​​{1}}后方,并且2: B->.->A转过来。在此之后,很明显,他们将在B1次移动中相遇。因此,如果循环存在并从某个位置2开始,那么我们最多只进行P次迭代。

答案 2 :(得分:-1)

//if you just want to check if there is a loop

loop = false;
item = head-of-list; 
while (item != nil)
{
   if (item.next < 0) 
   {
      loop = true; 
      break; 
   }
   else
   {
      actual = item;
      item = item.next; 
      actual.next = actual.next * -1; 
   }
} 

return loop;