CodeGym /Cursos /JAVA 25 SELF /Queue, Deque, Stack: trabajo con colas y pilas

Queue, Deque, Stack: trabajo con colas y pilas

JAVA 25 SELF
Nivel 27 , Lección 2
Disponible

1. Interfaz Queue: cola clásica (FIFO)

En programación, como en la vida, hay situaciones en las que no solo es importante almacenar un conjunto de elementos, sino gestionar el orden en que se procesan. Imagina una cola en el supermercado: quien está más cerca del comienzo se atiende antes. Este es el principio FIFO — «primero en entrar — primero en salir». En cambio, una pila de platos en un armario funciona según el principio LIFO — «último en entrar — primero en salir». En Java, estos principios se reflejan en colecciones: colas Queue, colas de doble extremo Deque y pilas Stack.

Dónde se utilizan:

  • Procesamiento de tareas por orden de llegada (cola de trabajos, impresión de documentos, manejo de eventos).
  • Implementación de deshacer/rehacer (undo/redo) — pila.
  • Análisis de expresiones, recorrido de árboles y grafos (búsqueda en anchura/profundidad), entre otros.

¿Qué es una cola?

Una cola (Queue) es una colección basada en el principio FIFO. Los elementos se añaden al final y se extraen del inicio. Como en una tienda: quien llegó antes, se atiende primero.

Métodos principales de la interfaz Queue

Método Qué hace Devuelve
offer(e)
Añade un elemento al final (sin excepción) true/false
add(e)
Añade un elemento al final (lanza excepción) true/Exception
poll()
Elimina y devuelve el primer elemento elemento/null
remove()
Elimina y devuelve el primer elemento elemento/Exception
peek()
Devuelve el primer elemento sin eliminarlo elemento/null
element()
Devuelve el primer elemento sin eliminarlo elemento/Exception

Seguramente has notado pares de métodos con comportamientos similares. La diferencia está en la «suavidad»: offer, poll, peek devuelven un valor especial en caso de fallo (normalmente null o false) y no lanzan excepciones, mientras que add, remove, element lanzan excepciones en situaciones límite (cola vacía, a veces desbordamiento).

Ejemplo: cola de tareas

import java.util.*;

public class QueueDemo {
    public static void main(String[] args) {
        Queue<String> tasks = new LinkedList<>();
        tasks.offer("Cepillarse los dientes");
        tasks.offer("Hacer ejercicios");
        tasks.offer("Tomar café");

        while (!tasks.isEmpty()) {
            String task = tasks.poll(); // Tomamos la tarea del principio de la cola
            System.out.println("Ejecutando: " + task);
        }
    }
}

Salida:

Ejecutando: Cepillarse los dientes
Ejecutando: Hacer ejercicios
Ejecutando: Tomar café

¿Por qué se usa con más frecuencia LinkedList?

Una interfaz es un contrato y hay varias implementaciones. A menudo se usa LinkedList porque añade/elimina rápidamente en ambos extremos. Sin embargo, una excelente alternativa es ArrayDeque. También hay variantes especializadas: PriorityQueue (cola por prioridades), de la que hablaremos más abajo.

2. Interfaz Deque: cola de doble extremo

Deque (Double Ended Queue, «dek») es una cola donde se pueden añadir y eliminar elementos por ambos extremos: desde el inicio y desde el final. Como un autobús con dos puertas: se puede entrar/salir por cualquiera de los lados.

Deque = soldado universal: puede funcionar como una cola normal (FIFO), como una pila (LIFO) y como un híbrido.

Métodos principales de la interfaz Deque

Método Qué hace Ejemplo de uso
addFirst(e)
Añadir al inicio
queue.addFirst("A")
addLast(e)
Añadir al final
queue.addLast("B")
removeFirst()
Eliminar y devolver desde el inicio
queue.removeFirst()
removeLast()
Eliminar y devolver desde el final
queue.removeLast()
peekFirst()
Ver el inicio (sin eliminar)
queue.peekFirst()
peekLast()
Ver el final (sin eliminar)
queue.peekLast()
offerFirst(e)
Añadir al inicio (sin excepción)
queue.offerFirst("C")
offerLast(e)
Añadir al final (sin excepción)
queue.offerLast("D")

Ejemplo: Deque como cola y como pila

import java.util.*;

public class DequeDemo {
    public static void main(String[] args) {
        Deque<String> deque = new ArrayDeque<>();

        // Lo usamos como cola (FIFO)
        deque.offerLast("A");
        deque.offerLast("B");
        deque.offerLast("C");
        System.out.println("Cola (FIFO):");
        while (!deque.isEmpty()) {
            System.out.println(deque.pollFirst());
        }

        // Lo usamos como pila (LIFO)
        deque.offerLast("1");
        deque.offerLast("2");
        deque.offerLast("3");
        System.out.println("Pila (LIFO):");
        while (!deque.isEmpty()) {
            System.out.println(deque.pollLast());
        }
    }
}

Salida:

Cola (FIFO):
A
B
C
Pila (LIFO):
3
2
1

¿Por qué ArrayDeque?

ArrayDeque es una implementación Deque rápida y compacta basada en array. Para pila y cola suele ser más rápida y fiable que la antigua Stack, y no tiene tamaño fijo (solo limitada por la memoria).

3. Stack: pila — último en entrar, primero en salir (LIFO)

Una pila es una colección con el principio LIFO: retiramos el elemento superior, que es el último añadido. En programación, una pila es útil para el historial de acciones (undo), el recorrido de estructuras recursivas (árboles/grafos), el cálculo de expresiones, etc.

Clase Stack (y por qué no conviene usarla)

En Java existe la clase Stack, que hereda de la obsoleta Vector. Hoy no se recomienda usarla en proyectos nuevos. Es preferible Deque/ArrayDeque.

Métodos de pila (Deque)

Método Qué hace
push(e)
Poner un elemento en la cima de la pila
pop()
Quitar y devolver el elemento superior
peek()
Ver el elemento superior

Atención: en Deque estas operaciones corresponden a los métodos addFirst/removeFirst/peekFirst, pero por compatibilidad también existen los nombres «de pila» push/pop/peek.

Ejemplo: pila con ArrayDeque

import java.util.*;

public class StackDemo {
    public static void main(String[] args) {
        Deque<String> stack = new ArrayDeque<>();
        stack.push("Primero");
        stack.push("Segundo");
        stack.push("Tercero");

        while (!stack.isEmpty()) {
            System.out.println(stack.pop());
        }
    }
}

Salida:

Tercero
Segundo
Primero

¿Por qué no Stack?

  • Stack está sincronizada (más lenta) y hereda de la obsoleta Vector.
  • ArrayDeque suele ser más rápida y compacta, no bloquea hilos.
  • Si ves Stack en código nuevo, normalmente es candidata a ser reemplazada por ArrayDeque.

4. Cuándo y qué usar

Estructura Principio Dónde usar Ejemplo de implementación
Queue FIFO Cola de tareas, procesamiento de eventos, impresión, colas de clientes
LinkedList, ArrayDeque, PriorityQueue
Stack LIFO Undo/redo, recursión, analizadores, recorrido de árboles
ArrayDeque
Deque FIFO/LIFO Buffers, palíndromos, colas bidireccionales, tareas universales
ArrayDeque, LinkedList

Ejemplos de la vida real:

  • Cola en el banco — Queue.
  • Historial de acciones en un editor — Stack.
  • Cola de autobuses, entrada/salida por ambos lados — Deque.

5. Ejemplos de código: implementamos cola y pila en una miniaplicación

Ejemplo 1: Cola de impresión de documentos

import java.util.*;

public class PrintQueueApp {
    public static void main(String[] args) {
        Queue<String> printQueue = new ArrayDeque<>();
        printQueue.offer("Documento1.pdf");
        printQueue.offer("Documento2.docx");
        printQueue.offer("Documento3.xls");

        while (!printQueue.isEmpty()) {
            String doc = printQueue.poll();
            System.out.println("Imprimiendo: " + doc);
        }
    }
}

Ejemplo 2: Pila de deshacer (undo)

import java.util.*;

public class UndoStackApp {
    public static void main(String[] args) {
        Deque<String> undoStack = new ArrayDeque<>();
        undoStack.push("Inserción de texto");
        undoStack.push("Cambio de color");
        undoStack.push("Eliminación de imagen");

        System.out.println("Última acción: " + undoStack.peek()); // Eliminación de imagen

        while (!undoStack.isEmpty()) {
            System.out.println("Deshacer: " + undoStack.pop());
        }
    }
}

Ejemplo 3: Cola de doble extremo

import java.util.*;

public class DequeApp {
    public static void main(String[] args) {
        Deque<String> deque = new ArrayDeque<>();
        deque.addFirst("A");
        deque.addLast("B");
        deque.addFirst("C");
        deque.addLast("D");

        System.out.println("Extraemos desde el inicio: " + deque.removeFirst()); // C
        System.out.println("Extraemos desde el final: " + deque.removeLast());   // D
        System.out.println("Queda: " + deque); // [A, B]
    }
}

6. Particularidades de implementación y matices

  • ArrayDeque es la implementación de cola/pila más rápida y universal para la mayoría de las tareas.
  • LinkedList también implementa Deque; puede ser útil, pero para colas cortas suele ser más lenta que ArrayDeque.
  • PriorityQueue es una cola por prioridad: el orden lo determinan las prioridades (naturales o a través de un Comparator); no es una cola FIFO normal.
  • Stack es obsoleta y está sincronizada; en proyectos nuevos se prefiere ArrayDeque.
  • Deque es cómoda porque permite trabajar tanto con el inicio como con el final de la estructura, cubriendo escenarios de colas y pilas con una única abstracción.

7. Errores típicos al trabajar con colas y pilas

Error n.º 1: Usar Stack en lugar de Deque.
Muchos principiantes ven la clase Stack y la eligen «por el nombre». En proyectos modernos, en su lugar se utiliza ArrayDeque (o LinkedList) con los métodos push/pop.

Error n.º 2: Violación del principio de la estructura.
Intentan acceder a elementos de una cola/pila por índice, por ejemplo queue.get(0) o stack.get(0). No se debe — usa los métodos correspondientes de colas y pilas (peek, poll, pop, etc.).

Error n.º 3: Uso de remove()/element()/add() sin comprobación.
Los métodos remove, element, add pueden lanzar una excepción si la estructura está vacía/saturada. Es más seguro usar los «suaves» offer, poll, peek, que devuelven valores especiales.

Error n.º 4: Uso de ArrayDeque con elementos null.
ArrayDeque no admite null. Intentar añadir null provocará NullPointerException.

Error n.º 5: Usar PriorityQueue como una cola normal.
En PriorityQueue el orden lo determinan las prioridades (naturales o definidas mediante un Comparator). Para un FIFO estricto, usa ArrayDeque o LinkedList.

Error n.º 6: Modificar la cola/pila durante un recorrido con for-each.
Eliminar elementos de una colección durante un for-each puede provocar ConcurrentModificationException. Para eliminar, usa un iterador o los métodos poll/pop en un bucle, como se muestra en los ejemplos.

1
Tarea
JAVA 25 SELF, nivel 27, lección 2
Bloqueada
Ver la siguiente tarea en el sistema 💼
Ver la siguiente tarea en el sistema 💼
1
Tarea
JAVA 25 SELF, nivel 27, lección 2
Bloqueada
Imitación del funcionamiento de la impresora y del historial de acciones 🖨️🔄
Imitación del funcionamiento de la impresora y del historial de acciones 🖨️🔄
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION