algorithm - 你能解释一下下面这段在链表中查找循环的代码片段是如何工作的吗?

标签 algorithm linked-list floyd-cycle-finding

此代码用于在单个链表中查找循环,我已从 http://blog.ostermiller.org/find-loop-singly-linked-list 了解了它但我无法理解为什么代码是这样写的。

此解决方案由 Stephen Ostermiller 设计,并由 Daniel Martin 证明为 O(n)。

function boolean hasLoop(Node startNode){
  Node currentNode = startNode;
  Node checkNode = null;
  int since = 0;
  int sinceScale = 2;
  do {
    if (checkNode == currentNode) return true;
    if (since >= sinceScale){
        checkNode = currentNode;
        since = 0;
        sinceScale = 2*sinceScale;
    }
    since++;
  } while (currentNode = currentNode.next());
  return false;
}

最后也提到了这一点:

This solution is O(n) because sinceScale grows linearly with the number of calls to next(). Once sinceScale is greater than the size of the loop, another n calls to next() may be required to detect the loop.

最佳答案

这是布伦特的循环寻找算法。 https://en.wikipedia.org/wiki/Cycle_detection#Brent%27s_algorithm

在大多数情况下,我比 Floyd 算法更喜欢它。它确实在 O(N) 时间内有效:

  • currentNode 放入列表的循环部分需要 O(N) 步。
  • 然后它将执行 O(N) 更多 步,直到 since == sinceScale,并且 checkNode 设置为 currentNode
  • 从那时起,checkNodecurrentNode 都在循环中。随着 sinceScale 变大,重置 checkNode 的频率会降低。当它足够大时,checkNode 将保持不变,直到 currentNode 一直绕着循环并检测到循环。每次将 sinceScale 缩放 2 确保这也在 O(N) 中发生。

对于在链表中查找循环,Floyd 算法或 Brent 算法都可以正常工作,但 Brent 算法在很多现实生活中更方便,因为从当前状态到下一个状态的代价很高,而且它会是移动 Floyd 算法所需的第二个“慢”指针是不切实际的。

关于algorithm - 你能解释一下下面这段在链表中查找循环的代码片段是如何工作的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50552276/

相关文章:

algorithm - 均匀划分连续的数字序列

Java扫描仪从文件中读取字符频率

你能帮我理解为什么链表上的以下代码给我一个段错误吗?

algorithm - 识别链表中循环的方法背后的逻辑

algorithm - 复杂度是 O(log(n) + log(n/2) + log(n/4) + log(n/8) + ... + log(2)) = O(log(n)) 吗?

计算列表中项目新位置的算法

与 realpath() 缓冲区混淆

c - 禁忌搜索算法总是在第二次迭代时崩溃

python - 检测周期不明来源

algorithm - 为什么在链表中查找循环时将指针增加 2,为什么不增加 3、4、5?