正如您所描述的,该数组变成了一个图(更准确地说是福雷斯特),其中每个顶点的出度正好为 1。这种图的组件只能由链组成,每个链都可能以单个循环结束。也就是说,每个组件的形状要么像 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
。S
如果您愿意跟踪 6 形组件两次,则 可以摆脱阵列。
另外我完全同意,如果不需要找到最大大小的循环,那么用于在链表中查找循环的古老“双指针”算法是优越的,因为它只需要恒定空间。