5

我试图在 .NET 中的 C++ 上找到这个算法,但找不到,我找到了这个:

// Best solution
function boolean hasLoop(Node startNode){
  Node slowNode = Node fastNode1 = Node fastNode2 = startNode;
  while (slowNode && fastNode1 = fastNode2.next() && fastNode2 = fastNode1.next()){
    if (slowNode == fastNode1 || slowNode == fastNode2) return true;
    slowNode = slowNode.next();
  }
  return false;
}

但似乎不对,还是我错了?我怎样才能真正证明我的兔子最终会遇到乌龟?提前感谢任何解释它是如何工作的proof

已编辑

关于这个解决方案,我发现在常规算法中他们只使用一个快速迭代器,但在这里他们使用两个,为什么?

4

3 回答 3

3

您找到的代码中的想法似乎很好。为了方便起见,使用了两个快速迭代器(尽管我很肯定这种“方便”,比如在while循环条件下放置很多“动作”,应该避免)。您可以使用一个变量以更易读的方式重写它:

while (fastNode && fastNode.next()) {
    if (fastNode.next() == slowNode || fastNode.next().next() == slowNode) {
        return true;
    }
    fastNode = fastNode.next().next();
    slowNode = slowNode.next();
}
于 2010-10-07T10:42:41.983 回答
2

算法是正确的。证明:

没有循环的情况是微不足道的:野兔会找到列表的末尾。

所以,有一个循环,兔子进入它,疯狂地跑来跑去。最终,乌龟到达循环的第一个节点。从这一点开始,两者都必须留在循环中:它们从一个节点到下一个节点的唯一方法是,最终回到循环的第一个节点。(绘制列表/图表的图片以说服自己。)

由于兔子移动得更快,它最终会赶上乌龟。根据循环的长度和进入它之前遍历的节点数(奇数还是偶数是重要的,所以有四种情况),这可能发生在奇数步或偶数步之后。这就是为什么兔子应该同时检查它的当前节点和下一个节点是否存在乌龟。(示例代码使用两个指针来实现这一点,尽管这并不是必需的。)

如需更正式的证明,请查看此Wikipedia 页面

于 2010-10-07T10:45:54.350 回答
0

该算法将在链表中找到一个循环。
可以使用一个快速节点来代替:

 function boolean hasLoop(Node startNode){
  Node slowNode = Node fastNode = startNode;
  while (slowNode && fastNode = fastNode.next() && fastNode = fastNode.next()){
    if (slowNode == fastNode) return true;
    slowNode = slowNode.next();
  }
  return false;
}
于 2010-10-07T10:41:05.557 回答