Red de conocimiento informático - Material del sitio web - Cómo comprobar si hay un ciclo en una lista enlazada unidireccional

Cómo comprobar si hay un ciclo en una lista enlazada unidireccional

1. El método más simple es usar un puntero para recorrer la lista vinculada. Cada vez que se encuentra un nodo, su dirección de memoria (en Java, puede usar object.hashcode ()) como clave en la tabla hash. tabla hash Cuando aparece una clave duplicada, indica que hay un anillo en la lista vinculada. La complejidad temporal de este método es O (n) y el espacio es O (n)

2. método de invertir el puntero, cada vez que pasa por un nodo, el puntero del nodo se invierte:

Inversión booleana (nodo*cabeza) {

Nodo *curr. = cabeza;

nodo * siguiente = cabeza- gt; siguiente;

curr->; siguiente = NULL

Y (siguiente! = NULL) {

if (next == head) { /*Volver al principio de la lista, por lo que hay un bucle*/

Siguiente - gt; next = curr

Devuelve VERDADERO

}

Nodo * temp = curr

curr = siguiente

siguiente = siguiente - gt siguiente;

curr->; next = temp

}

/*Al final de la lista, así que no hay bucle, rebobinemos la lista*/

siguiente = curr- gt; siguiente;

curr->; siguiente = NULL

y (siguiente! = NULL) {

Nodo * temp = curr

curr = siguiente

siguiente = siguiente - gt; siguiente

curr->; }

Regresar FALSO

}

Este parece ser un método extraño: cuando hay un ciclo, invertir el siguiente puntero eventualmente llegará a la cabeza del lista vinculada; Cuando no hay ciclo, invertir el siguiente puntero destruirá la estructura de la lista vinculada, por lo que al final la lista vinculada debe revertirse nuevamente. La complejidad espacial de este método es O (1). tres punteros adicionales; complejidad de tiempo para O (n), recorremos toda la lista vinculada como máximo dos veces (cuando no hay anillos en la lista vinculada).

La mayor desventaja de este método es que. No es seguro en situaciones de subprocesos múltiples. Al leer esta lista vinculada, el subproceso que verifica el bucle cambiará el estado de la lista vinculada, pero no hay garantía de que otros subprocesos obtengan los resultados correctos. , esta es la respuesta general esperada del entrevistador: punteros rápidos y punteros lentos

Boolean hash_loop(node*head){

Node * pf = head/*fast pointer*/<. /p >

Nodo *ps = encabezado; /*puntero lento*/

while(true) {

if(pf amp; amppf- gt; next)

pf = pf- gt; siguiente- gt;

Otro

Regresar FALSO

PS = PS- gt;

Si (ps == pf)

Devuelve VERDADERO

}

}

Nota El problema es que cuando el puntero lento (ps) ingresa al anillo, se necesitan como máximo n-1 pasos para encontrar el puntero rápido (pf), donde n es la longitud del anillo. En otras palabras, si el puntero rápido en el anillo puede omitir el puntero lento se puede demostrar simplemente por inducción.

(1) Cuando ps está en la posición I en el anillo y pf está en la posición I en el anillo,

(2) Cuando ps está en la posición I en el anillo y pf está en la posición i-2 en En el anillo, PS está en la posición I 1, pf está en la posición I en la siguiente iteración, por lo que PS y PF se encuentran en la posición i 2 en la siguiente iteración.

(3) Similar al proceso de razonamiento anterior, cuando ps está en I y PF está en i 1, después de n-1 iteraciones, se encontrarán en In-1, por lo que el número de pasos de el puntero lento no excederá n-1.

Extensiones:

Hay algunas extensiones para este problema. Por ejemplo, ¿cómo encontrar el nodo inicial del anillo? ¿Cómo desatar este anillo? La esencia de estos problemas es cómo encontrar nodos con "bordes posteriores".

Podemos resolver este problema usando una variación del método 3:

Boolean hash_loop(node*head) {

Node * pf = head /* Puntero rápido*/

Nodo *ps =head; /*Puntero lento*/

while(true) { /* paso 1, ¿hay un bucle? */

if(pf amp; amppf- gt; siguiente)

pf = pf- gt; siguiente- gt;

Otro

Devuelve FALSO

PS = PS- gt; siguiente

Si (ps == pf)

Break; > p>

}

/*El segundo paso, ¿cuánto dura el bucle?*/

int I = 0;

Hacer {

PS = PS- gt;

pf = pf- gt; siguiente

i; (ps!=pf)

/*Paso 3, use 2 punteros adicionales con una distancia de I para romper el bucle*/

ps = header;

pf = cabeza;

int j;

for(j = 0; j lt i; j ) { pf = pf- gt }

j = 0;

Y (ps!=pf) {

PS = PS- gt; siguiente;

pf = pf- gt;

j;

}

printf("El bucle comienza desde la posición d, la dirección del nodo es x", j, PS

);

/*El cuarto paso, romper el bucle*/

for(j = 0; j lt= I; j ){ PS = PS- gt;}//Comenzar desde el bucle Inicie el paso i-1 en el bucle

PS- gt; next = NULL // Rompe el bucle

Devuelve TRUE

}