Las colas basadas en listas enlazadas mantienen el modelo FIFO sin depender de un tamaño fijo de arreglo. Crecen y se encogen en función del número real de elementos, lo que evita reservar memoria ociosa.
final, sin necesidad de desplazar datos.Su costo principal es la sobrecarga de punteros y la necesidad de comprobar cada malloc/free, por lo que conviene encapsular la gestión de memoria en funciones pequeñas.
Un nodo almacena el valor y un enlace al siguiente. La cola mantiene punteros a frente y final para operar en tiempo constante:
typedef struct Nodo {
int dato;
struct Nodo *siguiente;
} Nodo;
typedef struct {
Nodo *frente;
Nodo *final;
int cantidad;
} ColaLista;
void inicializar(ColaLista *cola) {
cola->frente = NULL;
cola->final = NULL;
cola->cantidad = 0;
}
Al iniciar, ambos punteros deben apuntar a NULL para indicar que la cola está vacía.
El encolado crea un nodo nuevo, copia el dato y ajusta el puntero final. Siempre debe verificarse que la reserva de memoria funcione.
int enqueue(ColaLista *cola, int valor) {
Nodo *nuevo = malloc(sizeof(Nodo));
if (!nuevo) {
return 0;
}
nuevo->dato = valor;
nuevo->siguiente = NULL;
if (cola->cantidad == 0) {
cola->frente = nuevo;
} else {
cola->final->siguiente = nuevo;
}
cola->final = nuevo;
cola->cantidad++;
return 1;
}
Cuando la cola estaba vacía, frente y final pasan a apuntar al mismo nodo. En escenarios con interrupciones conviene envolver la operación con una sección crítica.
El desencolado recupera el valor del primer nodo, avanza el puntero y libera la memoria ocupada. Si el último elemento sale de la cola, ambos punteros vuelven a NULL.
int dequeue(ColaLista *cola, int *valor) {
if (cola->cantidad == 0) {
return 0;
}
Nodo *nodo = cola->frente;
*valor = nodo->dato;
cola->frente = nodo->siguiente;
if (!cola->frente) {
cola->final = NULL;
}
free(nodo);
cola->cantidad--;
return 1;
}
Esta implementación devuelve 0 si no existían elementos, lo que permite a la capa de aplicación decidir si reintentar o registrar un subflujo.
malloc debe propagarse para evitar nodos corruptos.cantidad, asignaciones pendientes y fallas facilita auditar la memoria en sistemas embebidos.Si los nodos almacenan estructuras grandes, conviene delegar la copia en funciones auxiliares para controlar que cada miembro se inicie correctamente.
void * o funciones de copia hace posible compartir el mismo código para distintos tipos.Documenta las convenciones (propiedad y destrucción de datos) para evitar dobles liberaciones cuando la cola transporte punteros.
El siguiente programa simula solicitudes que llegan a la cola, imprime su estado y realiza limpiezas antes de salir.
#include <stdio.h>
#include <stdlib.h>
typedef struct Nodo {
int dato;
struct Nodo *siguiente;
} Nodo;
typedef struct {
Nodo *frente;
Nodo *final;
int cantidad;
} ColaLista;
void inicializar(ColaLista *cola) {
cola->frente = NULL;
cola->final = NULL;
cola->cantidad = 0;
}
int enqueue(ColaLista *cola, int valor) {
Nodo *nuevo = malloc(sizeof(Nodo));
if (!nuevo) {
return 0;
}
nuevo->dato = valor;
nuevo->siguiente = NULL;
if (!cola->frente) {
cola->frente = nuevo;
} else {
cola->final->siguiente = nuevo;
}
cola->final = nuevo;
cola->cantidad++;
return 1;
}
int dequeue(ColaLista *cola, int *valor) {
if (!cola->frente) {
return 0;
}
Nodo *nodo = cola->frente;
*valor = nodo->dato;
cola->frente = nodo->siguiente;
if (!cola->frente) {
cola->final = NULL;
}
free(nodo);
cola->cantidad--;
return 1;
}
void imprimir(const ColaLista *cola) {
printf("[cola] cantidad=%d -> ", cola->cantidad);
for (Nodo *n = cola->frente; n; n = n->siguiente) {
printf("%d ", n->dato);
}
puts("");
}
void vaciar(ColaLista *cola) {
int descartado;
while (dequeue(cola, &descartado)) {
}
}
int main(void) {
ColaLista cola;
inicializar(&cola);
for (int i = 1; i <= 3; ++i) {
enqueue(&cola, i * 10);
}
imprimir(&cola);
int valor;
dequeue(&cola, &valor);
printf("desencolado: %d\n", valor);
imprimir(&cola);
enqueue(&cola, 99);
enqueue(&cola, 100);
imprimir(&cola);
while (dequeue(&cola, &valor)) {
printf("procesado: %d\n", valor);
}
imprimir(&cola);
vaciar(&cola);
return 0;
}
Prueba el ejemplo con distintas secuencias para verificar que los punteros regresen a NULL cuando la cola se vacía y que no se pierdan nodos.