如何在指针数组中找到无限循环?

时间:2013-04-18 20:56:14

标签: arrays algorithm pointers big-o infinite-loop

我有一个指针数组(这是算法,所以不要进入语言细节)。大多数情况下,此数组指向数组外部的位置,但它会降级到数组中的每个指针指向数组中的另一个指针的位置。最终,这些指针形成了一个无限循环。

因此,假设整个数组由指向数组中另一个位置的指针组成,并且从头开始,那么如何在时间和空间中找到效率最高的循环长度?我相信最好的时间效率是O(n),因为你必须遍历数组,最好的空间效率是O(1),虽然我不知道如何实现。

Index:  0  1  2  3  4  5  6
Value: *3 *2 *5 *4 *1 *1 *D

D是循环开始之前指向的数据。在这个例子中,循环是1,2,5并且它无限重复,但是索引0,3和4不是循环的一部分。

3 个答案:

答案 0 :(得分:4)

这是循环检测问题的一个实例。罗伯特·弗洛伊德于1960年发现了一种优雅的O(n)时间O(1)空间解决方案;它通常被称为"Tortoise and Hare"算法,因为它包括用两个指针遍历序列,一个指针移动速度是另一个指针的两倍。

这个想法很简单:对于某些k,循环必须有一个长度为k的循环。在每次迭代中,野兔移动两步并且乌龟移动一步,因此它们之间的距离比前一次迭代中的距离大一。因此,每k次迭代,它们是彼此相距k步的倍数,并且一旦它们都处于循环中(一旦乌龟到达就会发生),如果它们是...的倍数k分开,他们都指向同一个元素。

如果您需要知道的是周期的长度,那么等待野兔和乌龟到达同一地点;然后你沿着循环步进,计算步数,直到你再次回到同一个地方。在最坏的情况下,总的步数将是尾部的长度加上循环长度的两倍,其长度必须小于元素数量的两倍。

注意: 编辑第二段可能会使这个想法“更加明显”,无论这意味着什么。一个正式的证据很简单,实现也是如此,所以我没有提供。

答案 1 :(得分:0)

正如你所描述的那样,数组变成了一个图形(更恰当地说是一个图形),其中每个顶点都具有正好一个的度数。这种图的组成部分只能由链组成,每个链可能以单个循环结束。也就是说,每个组件的形状都像O或类似6.(我假设没有指针为空,但这很容易处理。你最终得到的是1形组件,根本没有循环。)

您可以通过“访问”跟踪所有这些组件,并使用“已访问”哈希或标记数组跟踪您曾经去过的地方。

这是一个算法。

编辑它只是针对每个节点一个子节点的情况简化的forrest的DFS,这消除了对堆栈(或递归)的需要,因为不需要回溯。

Let A[0..N-1] be the array of pointers.
Let V[0..N-1] be an array of boolean "visited" flags, initially false.
Let C[0..N-1] be an array if integer counts, initially zero.
Let S[0..N-1] be an array of "step counts" for each component trace.
longest = 0  // length of longest cycle
for i in 0..N-1, increment C[j] if A[i] points to A[j]
for each k such that C[k] = 0 
  // No "in edges", so must be the start of a 6-shaped component
  s = 0
  while V[k] is false
    V[k] = true
    S[k] = s
    s = s + 1
    k index of the array location that A[k] points to
  end
  // Loop found. Length is s - S[k]
  longest = max(longest, s - S[k])
end
// Rest of loops must be of the O variety
while there exists V[k] false
  Let k be such that V[k] is false.
  s = 0
  while V[k] is false
    V[k] = true
    s = s + 1
    k index of the array location that A[k] points to
  end
  // Found loop of length s
  longest = max(longest, s)
end      

空间和执行时间都与输入数组A的大小成正比。如果您愿意两次跟踪6个形状的组件,则可以删除S数组。

添加我完全同意,如果没有必要找到最大尺寸的周期,那么the ancient "two pointer" algorithm for finding cycles in a linked list 是优越的,因为它只需要恒定的空间。

答案 2 :(得分:0)

如果节点的元素指向其指向的节点的元素以及每个节点,则创建数组中元素的有向图,其中节点指向另一个节点。跟踪节点的indegree(指向它的指针的数量。)在创建图形时,如果存在具有indegree == 2的节点,则该节点是无限循环的一部分。

如果第一个元素包含在无限循环中,则上述操作失败,因此在算法开始之前,将1个indegree添加到第一个元素以解决此问题。

相关问题