Eu me pergunto se existe alguma lógica para reverter uma lista vinculada de forma simples usando apenas dois ponteiros.
O que se segue é usado para inverter a lista encadeada único usando três ponteiros nomeadamente p
, q
, r
:
struct node {
int data;
struct node *link;
};
void reverse() {
struct node *p = first,
*q = NULL,
*r;
while (p != NULL) {
r = q;
q = p;
p = p->link;
q->link = r;
}
first = q;
}
Existe alguma outra alternativa para reverter a lista vinculada? Qual seria a melhor lógica para reverter uma lista unida individualmente, em termos de complexidade de tempo?
Respostas:
Alguma alternativa? Não, isso é o mais simples possível e não há uma maneira fundamentalmente diferente de fazer isso. Este algoritmo já está no tempo O (n), e você não pode ficar mais rápido do que isso, pois você deve modificar cada nó.
Parece que seu código está no caminho certo, mas não está funcionando bem no formulário acima. Esta é uma versão funcional:
fonte
reverse()
função que deve ser configurada primeiro, eu acredito. Caso contrário, o código original funcionou bem quando conectado ao seu chicote de teste. Você recebe +1 de mim mesmo assim - mas uma explicação do que você considera os 'erros óbvios' melhoraria sua resposta.Eu odeio ser o portador de más notícias, mas não acho que sua solução de três pontos realmente funcione. Quando o usei no seguinte equipamento de teste, a lista foi reduzida a um nó, conforme a seguinte saída:
Você não obterá complexidade de tempo melhor do que sua solução, pois é O (n) e você precisa visitar todos os nós para alterar os ponteiros, mas você pode fazer uma solução com apenas dois ponteiros extras facilmente, conforme mostrado no código a seguir:
Este código resulta em:
que eu acho que é o que você estava procurando. Na verdade, ele pode fazer isso, pois, uma vez carregado
first
no ponteiro que percorre a lista, você pode reutilizá-lofirst
à vontade.fonte
first
ponteiro na própria lista ligada permite que a solução use apenas 2 ponteiros extras , mas 3 ponteiros no total ainda são necessários para isso.first
. Da mesma forma solução de três ponteiro do OP tevefirst
,p
,q
er
.fonte
Aqui está o código para inverter uma lista vinculada isoladamente em C .
E aqui está colado abaixo:
fonte
Sim. Tenho certeza de que você pode fazer isso da mesma forma que troca dois números sem usar um terceiro . Simplesmente lance os ponteiros para int / long e execute a operação XOR algumas vezes. Esse é um daqueles truques de C que tornam a pergunta divertida, mas não tem nenhum valor prático.
Você pode reduzir a complexidade de O (n)? Não, na verdade não. Basta usar uma lista duplamente vinculada se achar que vai precisar da ordem inversa.
fonte
Robert Sedgewick, " Algorithms in C ", Addison-Wesley, 3ª edição, 1997, [Seção 3.4]
Caso não seja uma lista cíclica, então NULL é o último link.
fonte
Apenas por diversão (embora a otimização da recursão da cauda deva impedi-la de consumir toda a pilha):
fonte
Para trocar duas variáveis sem o uso de uma variável temporária,
a maneira mais rápida é escrever em uma linha
Similarmente,
usando duas trocas
solução usando xor
solução em uma linha
A mesma lógica é usada para reverter uma lista vinculada.
fonte
intptr_t
). Embora seja interessante - trocar desta forma não é o ideal em sistemas modernos.Você precisa de um ponteiro de trilha que rastreará a lista.
Você precisa de duas dicas:
primeiro ponteiro para escolher o primeiro nó. segundo ponteiro para escolher o segundo nó.
Em processamento :
Ponteiro para mover trilha
Aponte o segundo nó para o primeiro nó
Mova o primeiro ponteiro um passo, atribuindo o segundo ponteiro a um
Mova o segundo ponteiro um passo, atribuindo o ponteiro da trilha ao segundo
}
fonte
Que tal o mais legível:
fonte
Aqui está uma versão mais simples em Java. Ele usa apenas dois ponteiros
curr
eprev
fonte
Calcule a complexidade de tempo do algoritmo que você está usando agora e ficará óbvio que não pode ser melhorado.
fonte
Não entendo por que é necessário voltar à cabeça, já que estamos passando isso como argumento. Estamos passando o chefe da lista de links, então podemos atualizar também. Abaixo está uma solução simples.
fonte
fonte
Não, nada mais rápido do que o O (n) atual pode ser feito. Você precisa alterar cada nó, então o tempo será proporcional ao número de elementos de qualquer maneira e isso é O (n) que você já tem.
fonte
Usar dois ponteiros enquanto mantém a complexidade de tempo de O (n), o mais rápido possível, só pode ser possível por meio da conversão de números de ponteiros e troca de seus valores. Aqui está uma implementação:
fonte
Eu tenho uma abordagem um pouco diferente. Eu queria fazer uso das funções existentes (como insert_at (índice), delete_from (índice)) para inverter a lista (algo como uma operação de deslocamento à direita). A complexidade ainda é O (n), mas a vantagem é o código mais reutilizado. Dê uma olhada no método another_reverse () e deixe-me saber o que vocês pensam.
fonte
fonte
fonte
Sim, existe uma maneira de usar apenas dois ponteiros. Isto é, criando uma nova lista encadeada onde o primeiro nó é o primeiro nó da lista fornecida e o segundo nó da primeira lista é adicionado no início da nova lista e assim por diante.
fonte
Aqui está minha versão:
Onde
fonte
Estou usando java para implementar isso e a abordagem é o desenvolvimento dirigido por teste, portanto, os casos de teste também estão anexados.
A classe Node que representa um único nó -
Classe de serviço que recebe o nó inicial como entrada e o reserva sem usar espaço extra.
E o caso de teste que cobre o cenário acima. Observe que você precisa de jarros junit. Estou usando testng.jar; você pode usar o que quiser ..
fonte
Um algoritmo simples se você usar a lista vinculada como uma estrutura de pilha:
O desempenho pode ser afetado desde a chamada de função adicional para add e malloc, de modo que os algoritmos de trocas de endereço são melhores, mas aquele realmente cria uma nova lista para que você possa usar opções adicionais como classificar ou remover itens se adicionar uma função de retorno de chamada como parâmetro para o reverter.
fonte
Aqui está uma abordagem um pouco diferente, mas simples em C ++ 11:
Saída aqui
fonte
A seguir está uma implementação usando 2 ponteiros (cabeça e r)
fonte
sizeof(size_t) < sizeof(ListNode*)
... usarstd::uintptr_t
.aqui está uma pequena solução simples ...
fonte
Você pode ter solução deste problema com a ajuda de apenas um ponteiro extra, que deve ser estático para a função reversa. Está em complexidade O (n).
fonte
Como alternativa, você pode usar recursão-
fonte
fonte
fonte