The "hare and tortoise" algorithm
(define gk-list?
(lambda (ls)
(let race ([h ls] [t ls])
(if (pair? h)
(let ([h (cdr h)])
(if (pair? h)
(and (not (eq? h t)) (race (cdr h) (cdr t)))
(null? h)))
(null? h)))))
The function will check if a list is proper list.
If (eq? h t) is true, then there is a cycle in the list, from there, let h keep running and t stay until h equal t again, we can know the length of the cycle.
(define test-list?
(lambda (ls)
(let race ((h ls) (t ls))
(if (pair? h)
(let ((h (cdr h)))
(if (pair? h)
(if (eq? h t)
(test-length h)
(race (cdr h) (cdr t)))
(null? h)))
(null? h)))))
(define test-length
(lambda (ls)
(let count ([from (cdr ls)] [cnt 1])
(if (eq? from ls)
cnt
(count (cdr from) (+ cnt 1))))))
#include <iostream>
using std::cout;
using std::endl;
struct item {
int value;
item *next;
item(int value): value(value), next(NULL) {}
};
struct result {
bool isList;
int cycleLength;
result(bool isList, int cycleLength):isList(isList), cycleLength(cycleLength) {}
void dump() {
cout << "{" << isList << "," << cycleLength << "}" << endl;
}
};
int getCycleLength(item *h)
{
item *from, *to;
int count;
to = h;
from = h->next;
for (count = 1; from != to; from = from->next, ++count);
return count;
}
result race(item *h, item* t)
{
for (;h != NULL; h = h->next, t = t->next) {
h = h->next;
if (h == NULL) return result(true, -1);
else if (h == t) return result(false, getCycleLength(h));
}
return result(true, -1);
}
result isList(item *list)
{
return race(list, list);
}
int main(int argc, char **argv)
{
item *a = new item(0),
*b = new item(1),
*c = new item(2);
a->next = b;
b->next = c;
c->next = a;
isList(a).dump();
return 0;
}