Cómo identificar un bucle en una lista vinculada individualmente

El algoritmo tortuga + liebre es asintóticamente óptimo tanto en términos de complejidad temporal como de espacio auxiliar. No puedes hacerlo significativamente mejor que eso.

También hay una solución diferente que todavía usa el tiempo O (duración de la lista) y la memoria O (1). El truco es utilizar la profundización iterativa. La solución consistirá en múltiples fases, numeradas a partir de 0. En la fase [matemática] k [/ matemática], use dos punteros P y Q de la siguiente manera:

  • Inicialice P al comienzo de la lista.
  • Mueva P por [matemática] 2 ^ k [/ matemática] pasos. Si en algún momento llega al final, responda que la lista es finita.
  • Inicializar Q a P.
  • Mueve Q por [matemática] 2 ^ k [/ matemática] pasos. Si en algún momento llega al final, responda que la lista es finita. Si después de un paso Q = P, responda que la lista tiene un ciclo.
  • Si llegaste a este paso, la fase actual finaliza. Incremente [math] k [/ math] y comience desde el principio.

Si la lista es finita, el algoritmo termina tan pronto como [math] 2 ^ k [/ math] excede su longitud. Si la lista tiene un ciclo, el algoritmo termina tan pronto como [math] 2 ^ k [/ math] excede tanto la duración del período anterior como la duración del período. En cualquier caso, se puede mostrar que la complejidad del tiempo total es lineal en la longitud de la lista. (Comente si esto no es obvio).

El uso del método de puntero lento y rápido se llama algoritmo de detección de bucle de Floyd (Detecta un bucle en una lista vinculada y encuentra el nodo donde comienza el bucle):
1. Inicialice dos punteros: un puntero lento ‘S’ y un puntero rápido ‘F’ para comenzar la lista
2. Mueva ‘S’ hacia adelante un nodo a la vez y mueva ‘F’ hacia adelante dos nodos a la vez.
3. Si en algún punto ‘S’ y ‘F’ apuntan al mismo nodo, entonces sabemos que hay un ciclo en la lista, de lo contrario no hay ciclo.
4. Después de detectar el bucle, volvemos a mover ‘S’ al inicio de la lista y mantenemos ‘F’ en el mismo punto de encuentro.
5. Ahora, esta vez, movemos tanto ‘S’ como ‘F’ hacia adelante un nodo a la vez hasta que se encuentren.
6. El nodo donde se encuentran es el inicio del ciclo.

Aquí está la solución:

Encontrar un bucle en una lista vinculada individualmente
Encontrar el bucle en una lista individualmente vinculada
Escriba una función C para detectar el bucle en una lista vinculada: GeeksforGeeks.

El problema con esta pregunta es que el algoritmo de tortuga y liebre no tiene desventajas reales.

Es lo mismo que el algoritmo de profundización iterativo (también bastante intuitivo) que Michal sugirió en el sentido de que los dos punteros se mantienen invariablemente dentro de un factor dos entre sí mientras se mueven más y más, pero es mucho más elegante.

Realmente es un algoritmo perfecto. Por supuesto, puede jugar con la cantidad de pasos que las tortugas y las liebres hacen cada iteración, pero esto podría uglificar su código y producir beneficios muy limitados, sea cual sea su aplicación.

Una solución simple con complejidad O (N) es colocar una bandera en cada nodo. Recorre la lista una vez para restablecer las banderas. Mientras recorre la lista por segunda vez, establece el indicador para cada nodo visitado. Si llega a un nodo con la bandera ya establecida, hay un bucle y el nodo es el principio (y el final) del bucle.

Editar: Seth Sims tiene toda la razón, esta es una respuesta incorrecta que no puede funcionar como se describe anteriormente. Sin embargo, los nodos se pueden crear (mientras se construye la lista) con las banderas establecidas en el valor correcto. Después de crear la lista, se pueden encontrar los bucles cambiando el valor de las banderas. Si no se detecta el bucle, los indicadores se pueden restablecer y la lista se puede modificar y volver a probar.

Detectar bucle en la lista de enlaces individuales.

  1. Use dos punteros FastPtr y SlowPtr e inicialice ambos en el encabezado de la Lista vinculada.
  2. Mueva FastPtr por dos nodos y SlowPtr por un nodo en cada iteración.
  3. Si FastPtr y SlowPtr se encuentran en alguna iteración, entonces hay un bucle en la lista vinculada.
  4. Si FastPtr llega al final de la Lista vinculada sin cumplir con SlowPtr, entonces no hay ningún bucle en la Lista vinculada.

público booleano DetectLoop ()

{

Nodo FastPtr = cabeza;

Nodo SlowPtr = cabeza;

while (FastPtr! = null && FastPtr.next! = null)

{

FastPtr = FastPtr.next.next;

SlowPtr = SlowPtr.next;

if (SlowPtr == FastPtr)

{return true;

}

falso retorno;

}

Agradable y detallada explicación sobre,

Cómo detectar el bucle en la lista vinculada, Cómo identificar el nodo de inicio del bucle en la lista vinculada y eliminar el bucle en la lista vinculada.

Detectar bucle, identificar el nodo de inicio del bucle y eliminar el bucle en la lista vinculada.

Claro: agregue cada puntero a un árbol.

Aunque solicitó el uso de un puntero rápido y lento, todavía le daré otra solución usando un HashMap. Siempre es bueno saber más de una forma de resolver un problema 🙂

  bool checkCycleHashMap () {
	 if (head == NULL || head-> Next () == NULL)
		 falso retorno;
	 std :: map  hash;
	 Nodo * temp = cabeza;
	 while (temp! = NULL) {
		 // Si no se encuentra
		 if (hash.find (temp) == hash.end ()) {
			 hash [temp] = verdadero;
			 temp = temp-> Siguiente ();
		 }
		 más 
			 falso retorno;
	 }
	 volver verdadero;
 }