Floyd's cycle-finding algorithm
Floyd’s cycle-finding algorithm 是一个经典的算法,用来检测一个链表中是否有环这种问题。因为它使用了两个指针,快的指针被称为兔子,慢的指针被称为乌龟,所以这个算法又被称为“龟兔算法”。
Emacs 源代码中有它的一个完美实现,我们可以看 src/eval.c 中的 signal_error()。
[c]
/ Signal `error’ with message S, and additional arg ARG.
If ARG is not a genuine list, make it a one-element list. /
void
signal_error (s, arg)
char *s;
Lisp_Object arg;
{
Lisp_Object tortoise, hare;
hare = tortoise = arg;
while (CONSP (hare))
{
hare = XCDR (hare);
if (!CONSP (hare))
break;
hare = XCDR (hare);
tortoise = XCDR (tortoise);
if (EQ (hare, tortoise))
break;
}
if (!NILP (hare))
arg = Fcons (arg, Qnil); / Make it a list. /
xsignal (Qerror, Fcons (build_string (s), arg));
}
[/c]
上面有一些 lisp “词汇” 可能你看不懂,翻译成你看得懂的代码如下。
[c]
bool
list_has_cycle(NODE list)
{
NODE tortoise, *hare;
hare = tortoise = list;
while (hare)
{
hare = hare->next;
if (!hare)
break;
hare = hare->next;
tortoise = tortoise->next;
if (hare == tortoise)
break;
}
if (hare)
return true;
return false;
}
[/c]