Desafio C
Inverter lista encadeada
Enunciado
Implemente uma função inverter que inverte a ordem dos nós de uma lista encadeada simples, retornando o novo ponteiro para a cabeça. A inversão deve ser feita in-place, ou seja, sem alocar novos nós. Além disso, garanta que a memória original seja preservada (nenhum nó é liberado).
Requisitos
- A função deve inverter a lista alterando apenas os ponteiros
prox. - Não alocar novos nós.
- Retornar a nova cabeça (que era o último nó).
- A lista original deve ser modificada in-place.
Código inicial
#include <stdio.h>
#include <stdlib.h>
typedef struct No {
int valor;
struct No *prox;
} No;
No* inverter(No *head) {
// TODO: implemente
}
void imprimir(No *head) {
for (No *p = head; p; p = p->prox)
printf("%d -> ", p->valor);
printf("NULL\n");
}
int main(void) {
// criar lista: 1 -> 2 -> 3 -> 4 -> NULL
// inverter
// imprimir resultado
return 0;
}
Saída esperada
4 -> 3 -> 2 -> 1 -> NULL
Ver dica
Use três ponteiros: ant, atual e prox. A cada iteração, inverta o ponteiro prox do nó atual para apontar para o anterior.
Mostrar solução
#include <stdio.h>
#include <stdlib.h>
typedef struct No {
int valor;
struct No *prox;
} No;
No* inverter(No *head) {
No *ant = NULL;
No *atual = head;
No *prox = NULL;
while (atual) {
prox = atual->prox; // guarda o próximo
atual->prox = ant; // inverte o ponteiro
ant = atual; // avança ant
atual = prox; // avança atual
}
return ant; // nova cabeça
}
void imprimir(No *head) {
for (No *p = head; p; p = p->prox)
printf("%d -> ", p->valor);
printf("NULL\n");
}
No* inserir_fim(No *head, int valor) {
No *novo = malloc(sizeof(No));
novo->valor = valor;
novo->prox = NULL;
if (!head) return novo;
No *p = head;
while (p->prox) p = p->prox;
p->prox = novo;
return head;
}
void liberar(No *head) {
while (head) {
No *prox = head->prox;
free(head);
head = prox;
}
}
int main(void) {
No *lista = NULL;
lista = inserir_fim(lista, 1);
lista = inserir_fim(lista, 2);
lista = inserir_fim(lista, 3);
lista = inserir_fim(lista, 4);
lista = inverter(lista);
imprimir(lista);
liberar(lista);
return 0;
}
Passo a passo
- Inicializamos
ant = NULL,atual = headeprox = NULL. - Enquanto
atualnão forNULL:prox = atual->proxguarda o próximo nó antes de modificar.atual->prox = antinverte o ponteiro do nó atual para o anterior.ant = atualavança o anterior.atual = proxavança para o próximo nó.
- Ao final,
antaponta para a nova cabeça (último nó da lista original). - Retornamos
ant. - No
main, criamos a lista, invertemos e imprimimos.
Por que funciona
A inversão é feita iterativamente, revertendo o sentido dos ponteiros. Cada nó passa a apontar para o seu antecessor. O ponteiro prox evita perder o resto da lista. No final, o antigo último nó se torna a nova cabeça.
Erros comuns
- Não guardar o próximo nó antes de inverter: se fizer
atual->prox = antsem salvarprox, perde-se o resto da lista. - Retornar
headem vez deant: a nova cabeça éant. - Esquecer de inicializar
ant = NULL: o primeiro nó deve apontar paraNULL. - Modificar a lista e não liberar depois: a memória ainda precisa ser liberada no final.
Outra forma de resolver
Usar recursão:
No* inverter_rec(No *head) {
if (!head || !head->prox) return head;
No *nova = inverter_rec(head->prox);
head->prox->prox = head;
head->prox = NULL;
return nova;
}
Essa abordagem é elegante, mas usa pilha de recursão, podendo estourar para listas muito longas.
Saída esperada
4 -> 3 -> 2 -> 1 -> NULL