Este tema se concentra en las operaciones indispensables de una cola lineal basada en arrays. Cada rutina mantiene la complejidad O(1) y valida los estados de la estructura antes de modificarla.
enqueue inserta un nuevo elemento al final. Debe verificar que no se haya alcanzado la capacidad. Devuelve 1 si el valor ingresó y 0 en caso contrario.
int enqueue(Cola *cola, int valor) {
if (cola->final == CAPACIDAD) {
return 0;
}
cola->datos[cola->final++] = valor;
cola->cantidad++;
return 1;
}
Se recomienda encapsular la constante CAPACIDAD en un #define o enum y centralizar la inicialización en una función que ponga a cero todos los campos.
dequeue extrae el elemento ubicado en frente. Si la cola está vacía retorna 0 y deja el parámetro de salida sin modificar.
int dequeue(Cola *cola, int *valor) {
if (cola->cantidad == 0) {
return 0;
}
*valor = cola->datos[cola->frente++];
cola->cantidad--;
if (cola->frente == cola->final) {
cola->frente = 0;
cola->final = cola->cantidad;
}
return 1;
}
El reinicio opcional de índices evita que frente continúe creciendo indefinidamente cuando la cola vuelve a quedar vacía.
peek consulta el próximo elemento a atender sin retirarlo. Devuelve un valor centinela (por ejemplo -1) cuando la cola está vacía. Alternativamente puede retornar un código y escribir el resultado en un puntero.
int peek(const Cola *cola) {
if (cola->cantidad == 0) {
return -1;
}
return cola->datos[cola->frente];
}
En contextos donde el dato -1 es válido, conviene usar una función similar a dequeue con retorno entero y parámetro de salida.
Permite consultar si hay elementos pendientes. Resulta útil para las capas que consumen la cola sin conocer su implementación interna.
int esVacia(const Cola *cola) {
return cola->cantidad == 0;
}
Complementa a isEmpty para evitar encolados cuando ya no queda espacio disponible.
int esLlena(const Cola *cola) {
return cola->final == CAPACIDAD;
}
Instrumentar una función de depuración que recorra desde frente hasta final ayuda a inspeccionar el estado de la estructura mientras se prueban las operaciones.
void imprimir(const Cola *cola) {
printf("[cola] frente=%d final=%d cantidad=%d -> ", cola->frente, cola->final, cola->cantidad);
for (int i = cola->frente; i < cola->final; ++i) {
printf("%d ", cola->datos[i]);
}
puts("");
}
Este tipo de asistencia visual es clave cuando se integran colas en hilos o interrupciones.
isEmpty y isFull del estado real.Detectar a tiempo estos errores evita comportamientos no deterministas en sistemas embebidos o servicios concurrentes.
El siguiente ejemplo combina todas las operaciones presentadas y ejecuta una serie de pruebas básicas. Es un archivo main.c autocontenido listo para copiar en CLion u otro IDE.
#include <stdio.h>
#define CAPACIDAD 6
typedef struct {
int datos[CAPACIDAD];
int frente;
int final;
int cantidad;
} Cola;
void inicializar(Cola *cola) {
cola->frente = 0;
cola->final = 0;
cola->cantidad = 0;
}
int esVacia(const Cola *cola) {
return cola->cantidad == 0;
}
int esLlena(const Cola *cola) {
return cola->final == CAPACIDAD;
}
int enqueue(Cola *cola, int valor) {
if (esLlena(cola)) {
return 0;
}
cola->datos[cola->final++] = valor;
cola->cantidad++;
return 1;
}
int dequeue(Cola *cola, int *valor) {
if (esVacia(cola)) {
return 0;
}
*valor = cola->datos[cola->frente++];
cola->cantidad--;
if (cola->frente == cola->final) {
cola->frente = 0;
cola->final = cola->cantidad;
}
return 1;
}
int peek(const Cola *cola) {
if (esVacia(cola)) {
return -1;
}
return cola->datos[cola->frente];
}
void imprimir(const Cola *cola) {
printf("[cola] frente=%d final=%d cantidad=%d -> ", cola->frente, cola->final, cola->cantidad);
for (int i = cola->frente; i < cola->final; ++i) {
printf("%d ", cola->datos[i]);
}
puts("");
}
int main(void) {
Cola cola;
inicializar(&cola);
enqueue(&cola, 10);
enqueue(&cola, 20);
enqueue(&cola, 30);
imprimir(&cola);
printf("Peek inicial: %d\n", peek(&cola));
int valor;
while (dequeue(&cola, &valor)) {
printf("Dequeue: %d\n", valor);
if (valor == 20) {
enqueue(&cola, 99);
}
}
imprimir(&cola);
printf("Estado final vacio: %d\n", esVacia(&cola));
return 0;
}
Este flujo permite observar cómo se comporta la cola cuando se encolan elementos después de haber desencolado y cómo reaccionan las funciones de estado.