4 - Operaciones en colas lineales

Este tema se concentra en las operaciones indispensables de una cola lineal basada en listas fijas. Cada rutina mantiene la complejidad O(1) y valida los estados de la estructura antes de modificarla.

4.1 Enqueue

encolar inserta un nuevo elemento al final. Debe verificar que no se haya alcanzado la capacidad. Devuelve el nuevo tamaño o lanza un error si la cola está llena.

def encolar(self, valor):
  if self.final == self.capacidad:
    raise OverflowError("Cola llena")
  self.datos[self.final] = valor
  self.final += 1
  self.cantidad += 1
  return self.cantidad

Se recomienda encapsular la constante CAPACIDAD como atributo de clase y centralizar la inicialización en __init__ para asegurar estados coherentes.

4.2 Dequeue

desencolar extrae el elemento ubicado en frente. Si la cola está vacía lanza una excepción o devuelve un valor centinela, según el contrato que definas.

def desencolar(self):
  if self.cantidad == 0:
    raise IndexError("Cola vacia")
  valor = self.datos[self.frente]
  self.frente += 1
  self.cantidad -= 1
  if self.frente == self.final:
    self.frente = 0
    self.final = self.cantidad
  return valor

El reinicio opcional de índices evita que frente continúe creciendo indefinidamente cuando la cola vuelve a quedar vacía.

4.3 Peek

peek consulta el próximo elemento a atender sin retirarlo. Devuelve None cuando la cola está vacía.

def peek(self):
  if self.cantidad == 0:
    return None
  return self.datos[self.frente]

En contextos donde None es un dato válido, conviene exponer una variante que lance excepción para distinguir ambos casos.

4.4 isEmpty

Permite consultar si hay elementos pendientes. Resulta útil para las capas que consumen la cola sin conocer su implementación interna.

def es_vacia(self):
  return self.cantidad == 0

4.5 isFull

Complementa a isEmpty para evitar encolados cuando ya no queda espacio disponible.

def es_llena(self):
  return self.final == self.capacidad

4.6 Imprimir la cola

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.

def imprimir(self):
  contenido = " ".join(str(self.datos[i]) for i in range(self.frente, self.final))
  print(f"[cola] frente={self.frente} final={self.final} cantidad={self.cantidad} -> {contenido}")

Este tipo de asistencia visual es clave cuando se integran colas en hilos o interrupciones.

4.7 Errores comunes

  • No validar cola llena: provoca escrituras fuera de la lista o sobre datos no consumidos.
  • No actualizar el contador: desconecta las funciones isEmpty y isFull del estado real.
  • Olvidar reiniciar los índices: impide reusar la cola tras consumir todos los elementos.
  • Retornar referencias internas: copiar el dato antes de devolverlo evita exponer la lista.

Detectar a tiempo estos errores evita comportamientos no deterministas en sistemas embebidos o servicios concurrentes.

4.8 Código completo listo para Python

El siguiente ejemplo combina todas las operaciones presentadas y ejecuta una serie de pruebas básicas. Es un archivo main.py autocontenido listo para copiar y ejecutar con Python.

CAPACIDAD = 6


class Cola:
  def __init__(self, capacidad=CAPACIDAD):
    self.capacidad = capacidad
    self.datos = [None] * capacidad
    self.frente = 0
    self.final = 0
    self.cantidad = 0

  def es_vacia(self):
    return self.cantidad == 0

  def es_llena(self):
    return self.final == self.capacidad

  def encolar(self, valor):
    if self.es_llena():
      raise OverflowError("Cola llena")
    self.datos[self.final] = valor
    self.final += 1
    self.cantidad += 1

  def desencolar(self):
    if self.es_vacia():
      raise IndexError("Cola vacia")
    valor = self.datos[self.frente]
    self.frente += 1
    self.cantidad -= 1
    if self.frente == self.final:
      self.frente = 0
      self.final = self.cantidad
    return valor

  def peek(self):
    return None if self.es_vacia() else self.datos[self.frente]

  def imprimir(self):
    contenido = " ".join(str(self.datos[i]) for i in range(self.frente, self.final))
    print(f"[cola] frente={self.frente} final={self.final} cantidad={self.cantidad} -> {contenido}")


if __name__ == "__main__":
  cola = Cola()

  cola.encolar(10)
  cola.encolar(20)
  cola.encolar(30)
  cola.imprimir()

  print("Peek inicial:", cola.peek())

  while not cola.es_vacia():
    valor = cola.desencolar()
    print("Dequeue:", valor)
    if valor == 20:
      cola.encolar(99)

  cola.imprimir()
  print("Estado final vacio:", cola.es_vacia())

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.