Estos ejercicios amplían los temas anteriores y ayudan a consolidar la manipulación de listas enlazadas. Cada punto incluye una sugerencia de implementación en C.
size_t lista_contar(const Lista *lista) {
size_t total = 0;
const Nodo *reco = lista->cabeza;
while (reco) {
++total;
reco = reco->sig;
}
return total;
}
void lista_invertir(Lista *lista) {
Nodo *prev = NULL;
Nodo *curr = lista->cabeza;
while (curr) {
Nodo *sig = curr->sig;
curr->sig = prev;
prev = curr;
curr = sig;
}
lista->cabeza = prev;
}
Una estrategia simple es usar ordenamiento por inserción, aunque se pueden aplicar algoritmos más eficientes (merge sort).
void lista_ordenar(Lista *lista) {
if (!lista->cabeza || !lista->cabeza->sig) return;
Nodo *ordenada = NULL;
while (lista->cabeza) {
Nodo *curr = lista->cabeza;
lista->cabeza = curr->sig;
if (!ordenada || curr->valor < ordenada->valor) {
curr->sig = ordenada;
ordenada = curr;
} else {
Nodo *reco = ordenada;
while (reco->sig && reco->sig->valor < curr->valor) {
reco = reco->sig;
}
curr->sig = reco->sig;
reco->sig = curr;
}
}
lista->cabeza = ordenada;
}
void lista_eliminar_duplicados(Lista *lista) {
for (Nodo *curr = lista->cabeza; curr; curr = curr->sig) {
Nodo *prev = curr;
Nodo *reco = curr->sig;
while (reco) {
if (reco->valor == curr->valor) {
prev->sig = reco->sig;
free(reco);
reco = prev->sig;
} else {
prev = reco;
reco = reco->sig;
}
}
}
}
Lista lista_fusionar(const Lista *a, const Lista *b) {
Lista resultado = {0};
const Nodo *recoA = a->cabeza;
const Nodo *recoB = b->cabeza;
while (recoA || recoB) {
if (recoB == NULL || (recoA && recoA->valor < recoB->valor)) {
lista_insertar_final(&resultado, recoA->valor);
recoA = recoA->sig;
} else {
lista_insertar_final(&resultado, recoB->valor);
recoB = recoB->sig;
}
}
return resultado;
}
El algoritmo de Floyd (tortuga y liebre) recorre la lista con dos punteros a velocidades distintas. Si hay un ciclo, ambos punteros se encontrarán; de lo contrario, el puntero rápido llegará a NULL. Detectar ciclos evita loops infinitos y fugas de memoria en listas circulares no deseadas.
bool lista_tiene_ciclo(const Lista *lista) {
const Nodo *lento = lista->cabeza;
const Nodo *rapido = lista->cabeza;
while (rapido && rapido->sig) {
lento = lento->sig;
rapido = rapido->sig->sig;
if (lento == rapido) return true;
}
return false;
}