<Estructura de datos> Lista enlazada circular unidireccional

contenido

1. Introducción de ejemplos

2. ¿Qué es una lista enlazada con un anillo?

3. Ideas para resolver problemas

4. Problemas de expansión

   (1) Lento da 1 paso a la vez y rápido da 2 pasos a la vez. ¿Puedes alcanzarlo?

   (2) Lento da 1 paso a la vez, rápido da 3 pasos a la vez, ¿puedes alcanzarlo? rápido ¿qué tal 4 pasos a la vez? ¿Qué pasa con n pasos?

   (3) ¿Dónde está el punto de entrada del bucle de la lista enlazada?


1. Introducción de ejemplos

  •  Enlace directo:

lista enlazada circular

  • tema:

2. ¿Qué es una lista enlazada con un anillo?

 En una lista enlazada simple normal, cada nodo está enlazado en secuencia, y el último nodo apunta a NULL, de la siguiente manera:

 El último nodo de la lista enlazada con un anillo ya no apunta a NULL, sino que apunta a cualquier nodo anterior, formando así una lista enlazada con un anillo, y el ciclo continúa. como sigue:

3. Ideas para resolver problemas

Podemos abstraer un poco la imagen de arriba, antes de entrar al anillo, usamos una línea recta para representarlo, y después de entrar al anillo, usamos un círculo para representar el ciclo. Esta pregunta necesita usar la idea de encontrar el nodo intermedio y encontrar el puntero de velocidad del último k-ésimo nodo que explicamos anteriormente. Defina dos punteros lento y rápido para señalar el comienzo de la posición. Deje que lento dé un paso a la vez y rápido dé dos pasos a la vez.

Cuando lento camina a la mitad de la línea recta, rápido está justo en el punto de entrada del anillo.

 Suponga que cuando lento llega justo al punto de entrada del anillo, rápido va a la siguiente posición, en cuyo momento rápido comienza a ponerse al día.

 rápido comienza a alcanzar a lento, asumiendo que rápido comienza a alcanzar a lento en la siguiente posición

  • el código se muestra a continuación:
bool hasCycle(struct ListNode *head) {
    struct ListNode*slow=head;
    struct ListNode*fast=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(slow==fast)
        {
            return true;
        }
    }
    return false;
}

Solo desde el punto de vista de la desintegración, este problema no es complicado. Solo se puede resolver utilizando la idea de punteros rápidos y lentos. Este problema solo puede conducir a muchos problemas dignos de nuestra discusión, para profundizar nuestra Comprensión de la lista circular enlazada Conocer los siguientes tres problemas de expansión:

4. Problemas de expansión

(1) Lento da 1 paso a la vez y rápido da 2 pasos a la vez. ¿Puedes alcanzarlo?

  •  Respuesta: Ciertamente.
  • demostrar:

Cuando el lento va al medio, el rápido debe entrar al ring y el rápido comienza a perseguir. Suponemos que después de que lento entra en el bucle, la distancia entre lento y rápido es N. En este momento, lento da 1 paso y rápido da 2 pasos, y la distancia entre ellos se acorta en 1 y se convierte en N-1. Y así sucesivamente, cada vez que persigues, la distancia se reduce en 1, y cuando la distancia se reduce a 0, te alcanzarás. Con todo, definitivamente se pondrá al día.

(2) Lento da 1 paso a la vez, rápido da 3 pasos a la vez, ¿puedes alcanzarlo? rápido ¿qué tal 4 pasos a la vez? ¿Qué pasa con n pasos?

  •  Respuesta: no necesariamente
  • demostrar:

Analicemos primero la situación en la que la lentitud da un paso a la vez y la rápida da 3 pasos a la vez. Supongamos que el lento da 1 paso, el rápido da 3 pasos y simplemente entra al ring, y cuando el lento apenas entra al ring, el rápido puede haber caminado 1 círculo. La situación específica depende del tamaño del ring. En este momento, la distancia entre el lento y rápido es N. y suponga que la longitud del anillo es C.

Lento da 1 paso a la vez, rápido da 3 pasos a la vez y la distancia se convierte en N-2. Se puede ver que cada vez que van rápido y lento, la distancia se acorta en 2. En este punto, no es difícil averiguarlo. Necesita ser clasificado y discutido. Cuando N es un número par, simplemente puede ponerse al día. Cuando N es un número impar, la distancia final de persecución es -1. En esta vez, necesitas perseguir de nuevo, lo que significa lento y rápido.La distancia entre ellos se convierte en C-1.

Continúe persiguiendo, de acuerdo con el análisis anterior, si C-1 es un número par, entonces puede ponerse al día. Si C-1 es un número impar, nunca se pondrá al día y será perseguido en un bucle inalámbrico, pero no se pondrá al día. La diferencia N entre ellos está determinada por la longitud antes de entrar en el anillo y la longitud del anillo, y estos dos son aleatorios, por lo que el valor de N es incierto, puede ser par o impar, y si la discusión continúa así ahora, un número impar se habrá ido para siempre.

De la misma manera, caminar rápido 4 pasos a la vez también es la misma discusión, que tampoco es necesariamente, pero esta vez, la distancia se acorta en 3 cada vez que camina. Cuando N es un múltiplo de 3, puede ponerse al día. Cuando no es un múltiplo de 3, debe continuar la discusión. Los zapatos para niños interesados ​​​​pueden continuar estudiando. La idea es la misma que dar 3 pasos rápidos a la vez. .

(3) ¿Dónde está el punto de entrada del bucle de la lista enlazada?

 Cuando calculamos la distancia recorrida por lento y rápido, el punto de entrada es naturalmente claro.

  • ley uno:

Lento da 1 paso a la vez, rápido da 2 pasos a la vez, luego rápido viaja el doble de lejos que lento

Antes de explicar en detalle, antes que nada, debemos aclarar que no existe tal cosa como decir que el puntero lento lento camina un círculo en él, y el puntero rápido rápido no ha alcanzado al lento, porque rápido toma 2 pasos a la vez, y lento da 1 paso a la vez. La distancia disminuye en 1 cada vez, por lo que solo se acercará más y más hasta que lo atrape. A lo sumo 1 vuelta más rápido, pero nunca exactamente 1 vuelta. Así que es fácil deducir cuánto han ido lento y rápido.

  • Suponer:
  1. [Encabezado de lista - - - punto de entrada]: L
  2. [Punto de entrada - - - Punto de encuentro]: X
  3. [Longitud del anillo]: C

Distancia recorrida por lento: L + X

Distancia recorrida rápido: L + N*C + X

  • explique:

Porque se mencionó anteriormente que el lento no llegará hasta el final y no será perseguido, por lo que es fácil deducir que la distancia del lento es L+X

Si el puntero rápido se mueve 2 pasos a la vez, es probable que el puntero rápido haya caminado varias veces antes de que el puntero lento entre en el punto de entrada porque el anillo es demasiado pequeño. En 3 frases cortas:

  1. L es muy pequeño, C es muy grande, antes de que lento entre en el anillo, rápido puede estar dentro del anillo y el círculo no se ha completado.
  2. L es muy grande, C es muy pequeña, antes de que Slow entrara al ring, rápido caminó muchos círculos en él.
  3. Pero después de que el lento entra al ring, dentro de un círculo, el rápido debe alcanzar al lento, y su distancia es como máximo C-1.

De acuerdo a lo dicho al principio, la distancia recorrida por rápido es el doble de la distancia recorrida por lento, y se puede enlistar la siguiente fórmula:

2*(L+X) = L + N*C + X

Después de la simplificación: L+X = N*C o L = N*C - X o L = (N-1)*C + (CX) o L + X = N*C

Use esta fórmula para probar: un puntero va desde la reunión, un puntero va desde la cabeza, ¡se encontrarán en el punto de entrada!

Porque la fórmula (N-1)*C indica que después de caminar N-1 círculos desde el punto de encuentro, regresa al punto de encuentro. En este momento, la distancia de CX volverá al punto de entrada. Se puede ver desde lo anterior que esta fórmula les hace volver al punto de entrada.

  • Utilice un problema práctico para resolver específicamente la ubicación de los puntos de entrada y salida:
  • Enlace directo:

Lista enlazada circular 2.0-->Buscar punto de entrada

  • tema:

  •  el código se muestra a continuación:
struct ListNode* detectCycle(struct ListNode* head) {
    struct ListNode* slow = head;
    struct ListNode* fast = head;
    while (fast && fast->next)
    {
        //判断是否是带环链表
        slow = slow->next;
        fast = fast->next->next;
        if (slow == fast)
        {
            struct ListNode* meet = slow;
            while (meet != head)
            {
                //求出相遇点
                meet = meet->next;
                head = head->next;
            }
            return meet;
        }
    }
    return NULL;
}
  • Hay otra forma de encontrar el punto de encuentro:

Después de encontrar el punto de encuentro, deja que el encuentro sea la cola y que el siguiente punto sea la cabeza de la nueva lista enlazada.

Este método es particularmente ingenioso y simplemente se convierte en el problema de encontrar la intersección de dos listas enlazadas. Debido a que la cola de la lista enlazada headA se encuentra en este momento, y la cola de la lista enlazada headB también se encuentra, lo que significa que las dos listas enlazadas deben intersecarse, y la intersección es el punto de entrada. las listas es exactamente lo que el blogger detalló en la publicación anterior del blog Explicación, sin demasiado énfasis aquí.

Supongo que te gusta

Origin blog.csdn.net/bit_zyx/article/details/123819416
Recomendado
Clasificación