<Estrutura de dados> Lista vinculada circular unidirecional

contente

1. Introdução de exemplos

2. O que é uma lista encadeada com um anel?

3. Ideias para solução de problemas

4. Problemas de expansão

   (1) Lento dá 1 passo de cada vez e rápido dá 2 passos de cada vez.

   (2) Lento dá 1 passo de cada vez, rápido dá 3 passos de cada vez, você consegue alcançá-lo? rápido como cerca de 4 passos de cada vez? E quanto a n passos?

   (3) Onde está o ponto de entrada do loop de lista encadeada?


1. Introdução de exemplos

  •  Link direto:

lista encadeada circular

  • tema:

2. O que é uma lista encadeada com um anel?

 Em uma lista encadeada simples normal, cada nó é vinculado em sequência e o último nó aponta para NULL, como segue:

 O último nó da lista encadeada com um anel não aponta mais para NULL, mas aponta para qualquer nó anterior, formando assim uma lista encadeada com um anel, e o ciclo continua. do seguinte modo:

3. Ideias para solução de problemas

Podemos abstrair um pouco a figura acima: antes de entrar no anel, usamos uma linha reta para representá-lo, e depois de entrar no anel, usamos um círculo para representar o ciclo. Esta questão precisa usar a ideia de encontrar o nó intermediário e encontrar o ponteiro de velocidade do último k-ésimo nó que explicamos anteriormente. Defina dois ponteiros lentos e rápidos para apontar para o início da posição. Deixe devagar dar um passo de cada vez e rápido dar dois passos de cada vez.

Quando lento caminha a meio caminho da linha reta, rápido está apenas no ponto de entrada do ringue.

 Suponha que quando lento apenas atinge o ponto de entrada do anel, rápido vai para a posição seguinte, momento em que rápido começa a alcançar o modo

 rápido começa a alcançar o lento, assumindo que o rápido começa a alcançar o lento na seguinte posição

  • código mostrar como abaixo:
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;
}

Apenas do ponto de vista da desintegração, esse problema não é complicado. Pode ser resolvido apenas usando a ideia de ponteiros rápidos e lentos. Esse problema por si só pode levar a muitos problemas dignos de nossa discussão, de modo a aprofundar nossa compreensão da lista circular vinculada. Conheça os três problemas de expansão a seguir:

4. Problemas de expansão

(1) Lento dá 1 passo de cada vez e rápido dá 2 passos de cada vez.

  •  Resposta: Certamente.
  • provar:

Quando o lento vai para o meio, o rápido deve entrar no ringue e o rápido começa a perseguir. Assumimos que depois que o lento entra no loop, a distância entre o lento e o rápido é N. Neste momento, o lento dá 1 passo e o rápido dá 2 passos, e a distância entre eles diminui em 1 e se torna N-1. E assim por diante, cada vez que você persegue, a distância é reduzida em 1 e, quando a distância é reduzida a 0, você o alcança. Enfim, com certeza vai pegar.

(2) Lento dá 1 passo de cada vez, rápido dá 3 passos de cada vez, você consegue alcançá-lo? rápido como cerca de 4 passos de cada vez? E quanto a n passos?

  •  Resposta: não necessariamente
  • provar:

Vamos primeiro discutir a situação em que o lento dá 1 passo de cada vez e o rápido dá 3 passos de cada vez. Suponha que lento dá 1 passo, rápido dá 3 passos e apenas entra no ringue, e quando lento apenas entra no ringue, rápido pode ter andado 1 círculo. A situação específica depende do tamanho do anel. Neste momento, a distância entre o lento e rápido é N. e suponha que o comprimento do anel seja C.

Lento dá 1 passo de cada vez, rápido dá 3 passos de cada vez e a distância se torna N-2. Pode-se ver que cada vez que vai rápido e devagar, a distância é encurtada em 2. Neste ponto, não é difícil descobrir. Ele precisa ser classificado e discutido. Quando N é um número par, você pode apenas alcançá-lo. Quando N é um número ímpar, a distância final da perseguição é -1. Em desta vez, você precisa perseguir novamente, o que significa lento e rápido.A distância entre se torna C-1.

Continue a perseguir, de acordo com a análise anterior, se C-1 for um número par, você poderá alcançá-lo. Se C-1 for um número ímpar, ele nunca alcançará e será perseguido em um loop sem fio, mas não alcançará. A diferença N entre eles é determinada pelo comprimento antes de entrar no anel e o comprimento do anel, e esses dois são aleatórios, então o valor de N é incerto, pode ser par ou ímpar, e se a discussão continuar como apenas agora, um número ímpar desaparecerá para sempre.

Da mesma forma, andar rápido 4 passos de cada vez também é a mesma discussão, o que também não é necessariamente, mas desta vez, a distância é encurtada em 3 cada vez que você anda. Quando N é um múltiplo de 3, você pode recuperar o atraso. Quando não é um múltiplo de 3, você precisa continuar a discussão. Os sapatos das crianças interessadas podem continuar estudando. A ideia é a mesma de dar 3 passos rápidos de cada vez .

(3) Onde está o ponto de entrada do loop de lista encadeada?

 Quando descobrimos a distância percorrida por lento e rápido, o ponto de entrada é naturalmente claro.

  • Lei um:

Lento dá 1 passo de cada vez, rápido dá 2 passos de cada vez, então rápido viaja duas vezes mais longe que lento

Antes de explicar em detalhes, antes de tudo, devemos deixar claro que não existe tal coisa de dizer que o ponteiro lento lento anda um círculo nele, e o ponteiro rápido rápido não alcançou o lento, porque rápido leva 2 passos de cada vez, e lento dá 1 passo de cada vez. A distância diminui em 1 a cada vez, então ele só vai se aproximar cada vez mais até ser pego. No máximo 1 volta mais rápido, mas nunca exatamente 1 volta. Portanto, é fácil deduzir o quanto foi lento e rápido.

  • Suponha:
  1. [Lista cabeça - - - ponto de entrada]: L
  2. [Ponto de entrada - - - Ponto de encontro]: X
  3. [Comprimento do anel]: C

Distância percorrida por lento: L + X

Distância percorrida rapidamente: L + N*C + X

  • explique:

Como foi mencionado anteriormente que o lento não percorrerá todo o caminho e não será perseguido, é fácil deduzir que a distância do lento é L + X

Se o ponteiro rápido se mover 2 passos de cada vez, é provável que o ponteiro rápido tenha andado várias vezes antes do ponteiro lento entrar no ponto de entrada porque o anel é muito pequeno. Em 3 frases curtas:

  1. L é muito pequeno, C é muito grande, antes do lento entrar no anel, o rápido pode estar dentro do anel e o círculo não foi concluído.
  2. L é muito grande, C é muito pequeno, antes do lento entrar no ringue, rápido andou muitos círculos nele
  3. Mas depois que o lento entra no ringue, dentro de um círculo, o rápido deve alcançar o lento, e sua distância é no máximo C-1

De acordo com o que foi dito no início, a distância percorrida pelo rápido é o dobro da distância percorrida pelo lento, e pode-se listar a seguinte fórmula:

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

Após simplificação: L+X = N*C ou L = N*C - X ou L = (N-1)*C + (CX) ou L + X = N*C

Use esta fórmula para provar: um ponteiro vai do encontro, um ponteiro vai da cabeça, eles se encontrarão no ponto de entrada!

Porque a fórmula (N-1)*C indica que depois de percorrer N-1 círculos do ponto de encontro, ele retorna ao ponto de encontro. Neste momento, a distância de CX retornará ao ponto de entrada. Pode ser visto de o acima que esta fórmula os faz Voltar ao ponto de entrada.

  • Use um problema prático para resolver especificamente a localização dos pontos de entrada e saída:
  • Link direto:

Lista vinculada circular 2.0-->Encontrar ponto de entrada

  • tema:

  •  código mostrar como abaixo:
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;
}
  • Há outra maneira de encontrar o ponto de encontro:

Depois de encontrar o ponto de encontro, deixe o encontro ser a cauda e deixe o próximo ponto ser a cabeça da nova lista vinculada

Esse método é particularmente engenhoso e se transforma no problema de encontrar a interseção de duas listas vinculadas. Como a cauda da lista encadeada headA se encontra neste momento, e a cauda da lista encadeada headB também se encontra, o que significa que as duas listas encadeadas devem se cruzar e a interseção é o ponto de entrada. listas é exatamente o que o blogueiro detalhou no post anterior do blog. Explicação, sem muita ênfase aqui.

Acho que você gosta

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