Algoritmo de detección de ciclo de Floyd en lista enlazada
Se da una lista enlazada cuyo punto de partida se denota por head, y puede haber o no un ciclo presente. Por ejemplo:
Aquí necesitamos hallar el punto C, es decir, el punto de partida del ciclo.
Algoritmo propuesto
El algoritmo se llama algoritmo de ciclo de Floyd o algoritmo de la tortuga y la liebre (Floyd’s Cycle Algorithm / Tortoise and Hare). Para averiguar el punto de partida del ciclo, necesitamos averiguar si siquiera existe un ciclo. Esto involucra dos pasos:
- Averiguar la presencia del ciclo.
- Hallar el punto de partida del ciclo.
Paso 1: presencia del ciclo
- Tomar dos punteros y .
- Ambos apuntarán inicialmente a la cabeza de la lista enlazada.
- se moverá un paso a la vez.
- se moverá dos pasos a la vez (el doble de velocidad que el puntero ).
- Comprobar si en algún momento apuntan al mismo nodo antes de que alguno (o ambos) llegue a null.
- Si apuntan al mismo nodo en cualquier punto de su recorrido, indica que efectivamente existe un ciclo en la lista enlazada.
- Si obtenemos null, indica que la lista enlazada no tiene ciclo.
Ahora que hemos averiguado si hay un ciclo presente en la lista enlazada, para el siguiente paso necesitamos hallar el punto de partida del ciclo, es decir, C.
Paso 2: punto de partida del ciclo
- Reiniciar el puntero a la cabeza de la lista enlazada.
- Mover ambos punteros un paso a la vez.
- El punto en el que se encuentren será el punto de partida del ciclo.
// Presence of cycle
public boolean hasCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
if(slow==fast){
return true;
}
}
return false;
}// Assuming there is a cycle present and slow and fast are point to their meeting point
slow = head;
while(slow!=fast){
slow = slow.next;
fast = fast.next;
}
return slow; // the starting point of the cycle.Por qué funciona
Paso 1: presencia del ciclo
Como el puntero se mueve al doble de velocidad que , podemos decir que en cualquier momento, habrá cubierto el doble de distancia que . También podemos deducir que la diferencia entre la distancia cubierta por ambos punteros aumenta en .
slow: 0 --> 1 --> 2 --> 3 --> 4 (distance covered)
fast: 0 --> 2 --> 4 --> 6 --> 8 (distance covered)
diff: 0 --> 1 --> 2 --> 3 --> 4 (difference between distance covered by both pointers)Sea la longitud del ciclo, y el número de pasos que necesita el puntero lento para llegar a la entrada del ciclo. Existe un entero positivo () tal que . Cuando el puntero lento se ha movido pasos, y el puntero rápido ha cubierto pasos, ambos punteros se encuentran dentro del ciclo. En este punto, hay una separación de entre ellos. Dado que la longitud del ciclo sigue siendo , esto significa que se encuentran en el mismo punto dentro del ciclo, resultando en su encuentro.
Paso 2: punto de partida del ciclo
Intentemos calcular la distancia cubierta por ambos punteros hasta el punto en que se encuentran dentro del ciclo.
,
,
- es la distancia total cubierta por el puntero lento.
- es la distancia total cubierta por el puntero rápido.
- es el número de pasos que ambos punteros necesitan dar para entrar al ciclo.
- es la distancia entre C y G, es decir, la distancia entre el punto de partida del ciclo y el punto de encuentro de ambos punteros.
- es el número de veces que el puntero lento ha dado vueltas dentro del ciclo, empezando y terminando en C.
- es el número de veces que el puntero rápido ha dado vueltas dentro del ciclo, empezando y terminando en C.
Resolviendo la fórmula obtenemos:
donde es un entero
Esto básicamente significa que pasos es lo mismo que dar un cierto número de vueltas completas en el ciclo e ir pasos hacia atrás. Como el puntero rápido ya está pasos por delante de la entrada del ciclo, si el puntero rápido se mueve otros pasos terminará en la entrada del ciclo. Y como dejamos que el puntero lento empiece al inicio de la lista enlazada, después de pasos también terminará en la entrada del ciclo. Así, si ambos se mueven pasos ambos se encontrarán en la entrada del ciclo.