Colecciones en Java — práctica con un contador de palabras, claves propias y colas de préstamos (y el HashMap que imprimía en un orden que no entendía)

Mi primer contador de palabras funcionó a la primera… o eso creí. Metí el texto, recorrí las palabras con un HashMap, imprimí el resultado y me quedé mirando la pantalla: las palabras salían revueltas. Ni por orden alfabético, ni por orden de aparición, ni por frecuencia. Pensé que había mezclado los datos sin querer y estuve media hora revisando el bucle. El bucle estaba bien. Lo que yo esperaba de un HashMap (un orden) es justo lo que un HashMap no promete.

Esa es la gracia de las colecciones: cada una promete cosas distintas, y la mayoría de los errores vienen de pedirle a una lo que prometía otra. Por eso hoy practicamos con tres programas en los que vas a comparar, romper y arreglar.

Si ya has leído la teoría de colecciones, este artículo es para aplicarla: contar palabras con un Map y sus tres sabores, ver qué pasa cuando tus propios objetos son claves de un HashSet o un HashMap, y montar colas y pilas de préstamos con Deque y PriorityQueue. Son programas de dificultad media. Cada uno trae el código comentado, la salida y las dudas que suelen surgir.

Antes de empezar

Conviene tener claro:

  • Que List admite repetidos y guarda el orden; Set no admite repetidos; Map asocia claves con valores.
  • Que HashSet y HashMap no garantizan ningún orden; LinkedHash... mantiene el de inserción y Tree... ordena.
  • Que HashSet y HashMap usan hashCode() para elegir el cubo y equals() para decidir si ya está.
  • Que merge(clave, 1, Integer::sum) sirve para contar.

Si alguno te suena dudoso, repasa la teoría antes de seguir.

Los tres programas son independientes. Crea una carpeta para cada uno y compílalos por separado.

Programa 1: contador de palabras con Map

Contar cuántas veces aparece cada palabra de un texto es el «hola mundo» de los Map. Lo haremos con los tres sabores a la vez para ver qué cambia.

La idea

Una palabra es una clave y su número de apariciones, el valor. Por cada palabra del texto: si ya estaba en el mapa, sumamos 1; si no, la añadimos con 1. Eso se puede escribir de dos maneras: con merge (corto) o con getOrDefault (explícito), y comprobaremos que dan lo mismo. Además, lo guardaremos a la vez en un HashMap, un TreeMap y un LinkedHashMap para comparar cómo se imprime cada uno.

El texto es una frase de Hamlet en inglés (sin tildes ni eñes, y de dominio público). Puedes cambiarla por cualquier otra, pero mantén las palabras separadas por espacios y en minúsculas.

Antes de ejecutar, piensa en qué orden saldrá cada mapa. ¿Alfabético? ¿De aparición? ¿Otro? Después lo comprobamos.

El código

Palabras.java

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class Palabras {
    public static void main(String[] args) {
        String texto = "to be or not to be that is the question whether it is nobler in the mind to suffer";
        String[] palabras = texto.split(" ");

        Map<String, Integer> hash = new HashMap<>();
        Map<String, Integer> arbol = new TreeMap<>();
        Map<String, Integer> enlazado = new LinkedHashMap<>();
        Map<String, Integer> manual = new HashMap<>();

        for (String p : palabras) {
            hash.merge(p, 1, Integer::sum);
            arbol.merge(p, 1, Integer::sum);
            enlazado.merge(p, 1, Integer::sum);
            manual.put(p, manual.getOrDefault(p, 0) + 1);   // la misma cuenta, sin merge
        }

        System.out.println("Palabras en total: " + palabras.length);
        System.out.println("Palabras distintas: " + hash.size());
        System.out.println("HashMap:       " + hash);
        System.out.println("TreeMap:       " + arbol);
        System.out.println("LinkedHashMap: " + enlazado);
        System.out.println("¿getOrDefault da lo mismo que merge? " + manual.equals(hash));

        String masRepetida = null;
        int max = 0;
        for (Map.Entry<String, Integer> e : arbol.entrySet()) {
            if (e.getValue() > max) {
                max = e.getValue();
                masRepetida = e.getKey();
            }
        }
        System.out.println("La más repetida: " + masRepetida + " (" + max + " veces)");

        List<String> unaVez = new ArrayList<>();
        for (Map.Entry<String, Integer> e : arbol.entrySet()) {
            if (e.getValue() == 1) {
                unaVez.add(e.getKey());
            }
        }
        System.out.println("Aparecen una sola vez: " + unaVez);
    }
}

Salida

Palabras en total: 19
Palabras distintas: 14
HashMap:       {mind=1, or=1, be=2, question=1, in=1, nobler=1, is=2, it=1, the=2, that=1, suffer=1, not=1, whether=1, to=3}
TreeMap:       {be=2, in=1, is=2, it=1, mind=1, nobler=1, not=1, or=1, question=1, suffer=1, that=1, the=2, to=3, whether=1}
LinkedHashMap: {to=3, be=2, or=1, not=1, that=1, is=2, the=2, question=1, whether=1, it=1, nobler=1, in=1, mind=1, suffer=1}
¿getOrDefault da lo mismo que merge? true
La más repetida: to (3 veces)
Aparecen una sola vez: [in, it, mind, nobler, not, or, question, suffer, that, whether]

Compruébalo a mano:

  • Total y distintas: el texto tiene 19 palabras, pero solo 14 distintas. El mapa tiene 14 entradas porque cada clave aparece una sola vez.
  • **TreeMap:** alfabético (be, in, is, it, mind…). Compara las claves con su orden natural.
  • **LinkedHashMap: por orden de primera aparición** (to, be, or, not…). La repetición de to no cambia su posición.
  • **HashMap: otro orden distinto, que no es ni el alfabético ni el de aparición. Es el que resulta de los códigos hash, y es el mismo cada vez que ejecutas este programa con estas** palabras, pero Java no lo promete. No te apoyes en él.
  • **to aparece 3 veces**, be, is y the 2, y el resto una sola.
  • **manual.equals(hash):** dos mapas son iguales si tienen las mismas parejas, sin importar el orden ni la implementación. Por eso getOrDefault y merge dan el mismo resultado.

Integer::sum es una referencia a método: «la función que suma dos enteros». merge la usa solo si la clave ya existía, para combinar el valor viejo con el 1 nuevo; si no existía, guarda el 1 tal cual.

Preguntas que te puedes hacer

**¿Por qué if (e.getValue() > max) y no >=?** Porque recorremos el TreeMap por orden alfabético: con > nos quedamos con la primera palabra que alcanza el máximo y, si hay empate, gana la alfabéticamente menor. Con >= ganaría la última del empate.

**¿Por qué recorro con entrySet() y no con keySet() y luego get?** Porque entrySet() te da la clave y el valor a la vez, en una sola pasada. Con keySet() tendrías que buscar cada valor con get, que es trabajo repetido.

¿Cuál de los tres uso? HashMap si solo quieres contar y buscar; TreeMap si luego vas a mostrar las palabras ordenadas; LinkedHashMap si quieres respetar el orden en que aparecieron.

¿Y si el texto tiene mayúsculas o signos de puntuación? Entonces The y the serían claves distintas. Lo normal es pasar el texto a minúsculas con toLowerCase() y separar con una expresión regular, por ejemplo split("\\W+"), que corta por cualquier cosa que no sea una letra.

Hacer mapa.put(p, mapa.get(p) + 1) sin comprobar antes si la clave existe. La primera vez get(p) devuelve null, y al sumarle 1 el programa se cae con NullPointerException. Por eso existen getOrDefault y merge.

Pruébalo tú

  1. Cambia el texto por otro tuyo y comprueba que el TreeMap sigue saliendo alfabético y el LinkedHashMap por primera aparición.
  2. Añade al programa una última línea que imprima las palabras que aparecen más de una vez, en orden alfabético.

Programa 2: tus objetos como claves

El programa que explica por qué el conjunto del principio de la teoría decía tener dos veces el mismo libro. Aquí lo ponemos con todos los matices.

La idea

Vamos a crear cinco versiones de «libro identificado por su ISBN». Con las cuatro primeras meteremos dos libros con el mismo ISBN en un HashSet:

  1. LibroNada: sin equals() ni hashCode().
  2. LibroEquals: solo equals().
  3. LibroCompleto: equals() y hashCode().
  4. LibroRecord: un record, que los genera solo.
  5. LibroMutable: cumple el contrato, pero su campo titulo se puede cambiar después de guardarlo.

Para cada uno, un método probar imprime si son equals, si tienen el mismo hashCode y cuántos elementos acaba teniendo el conjunto. Después usamos LibroCompleto como clave de un HashMap para contar ejemplares, y por último vemos qué pasa cuando la clave cambia después de guardarla.

Antes de ejecutar, apunta qué tamaño crees que dará cada conjunto. La segunda fila (solo equals) es la que más sorprende.

El código

Claves.java

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

public class Claves {

    static class LibroNada {
        final String isbn;
        LibroNada(String isbn) { this.isbn = isbn; }
    }

    static class LibroEquals {
        final String isbn;
        LibroEquals(String isbn) { this.isbn = isbn; }

        @Override
        public boolean equals(Object o) {
            return o instanceof LibroEquals otro && isbn.equals(otro.isbn);
        }
    }

    static class LibroCompleto {
        final String isbn;
        LibroCompleto(String isbn) { this.isbn = isbn; }

        @Override
        public boolean equals(Object o) {
            return o instanceof LibroCompleto otro && isbn.equals(otro.isbn);
        }

        @Override
        public int hashCode() {
            return Objects.hash(isbn);
        }

        @Override
        public String toString() {
            return "Libro " + isbn;
        }
    }

    record LibroRecord(String isbn) { }

    static class LibroMutable {
        private String titulo;
        LibroMutable(String titulo) { this.titulo = titulo; }
        void setTitulo(String titulo) { this.titulo = titulo; }

        @Override
        public boolean equals(Object o) {
            return o instanceof LibroMutable otro && titulo.equals(otro.titulo);
        }

        @Override
        public int hashCode() {
            return titulo.hashCode();
        }

        @Override
        public String toString() {
            return titulo;
        }
    }

    static void probar(String nombre, Object a, Object b) {
        Set<Object> conjunto = new HashSet<>();
        conjunto.add(a);
        conjunto.add(b);
        System.out.println(nombre + ": equals=" + a.equals(b)
                + ", mismo hashCode=" + (a.hashCode() == b.hashCode())
                + ", tamaño del conjunto=" + conjunto.size());
    }

    public static void main(String[] args) {
        System.out.println("== Dos objetos con el mismo ISBN ==");
        probar("Sin nada      ", new LibroNada("L-101"), new LibroNada("L-101"));
        probar("Solo equals   ", new LibroEquals("L-101"), new LibroEquals("L-101"));
        probar("equals+hash   ", new LibroCompleto("L-101"), new LibroCompleto("L-101"));
        probar("record        ", new LibroRecord("L-101"), new LibroRecord("L-101"));

        System.out.println("== Como clave de un HashMap ==");
        Map<LibroCompleto, Integer> copias = new HashMap<>();
        copias.merge(new LibroCompleto("L-101"), 1, Integer::sum);
        copias.merge(new LibroCompleto("L-102"), 1, Integer::sum);
        copias.merge(new LibroCompleto("L-101"), 1, Integer::sum);
        System.out.println("Copias: " + copias);

        System.out.println("== Clave que cambia después de guardarla ==");
        LibroMutable libro = new LibroMutable("Dune");
        Set<LibroMutable> estante = new HashSet<>();
        estante.add(libro);
        System.out.println("Antes de cambiar el título: contains=" + estante.contains(libro));
        libro.setTitulo("Dune (2.ª edición)");
        System.out.println("Después de cambiarlo:       contains=" + estante.contains(libro)
                + ", size=" + estante.size());
        System.out.println("Pero al recorrerlo sigue ahí: " + estante);
    }
}

Salida

== Dos objetos con el mismo ISBN ==
Sin nada      : equals=false, mismo hashCode=false, tamaño del conjunto=2
Solo equals   : equals=true, mismo hashCode=false, tamaño del conjunto=2
equals+hash   : equals=true, mismo hashCode=true, tamaño del conjunto=1
record        : equals=true, mismo hashCode=true, tamaño del conjunto=1
== Como clave de un HashMap ==
Copias: {Libro L-101=2, Libro L-102=1}
== Clave que cambia después de guardarla ==
Antes de cambiar el título: contains=true
Después de cambiarlo:       contains=false, size=1
Pero al recorrerlo sigue ahí: [Dune (2.ª edición)]

Compruébalo a mano:

  • Sin nada: ni equals ni mismo hash. Dos objetos distintos para Java: tamaño 2.
  • **Solo equals:** equals da true, pero el hash sigue siendo distinto. El HashSet mira primero el hash para elegir el cubo, así que ni se entera de que son iguales: tamaño 2. Es el fallo más traicionero, porque el código parece correcto.
  • **equals + hashCode:** el contrato completo. Tamaño 1.
  • **record:** lo mismo que el anterior, sin escribir nada. Compara todos los campos (aquí solo hay uno).
  • **HashMap con claves LibroCompleto:** las dos L-101 se reconocen como la misma clave y merge suma: L-101=2, L-102=1.
  • Clave que cambia: el libro sigue dentro del conjunto (size=1, y aparece al recorrerlo), pero contains da false. Es una pérdida silenciosa.

El hashCode de LibroMutable depende de titulo. Al guardarlo, el conjunto lo colocó en el cubo que correspondía al título "Dune". Tras cambiar el título, contains calcula un hash nuevo, mira en otro cubo y no encuentra nada, aunque el objeto esté ahí.

Preguntas que te puedes hacer

**¿Por qué no basta con equals()?** Porque HashSet y HashMap primero usan hashCode() para decidir en qué cubo mirar y solo comparan con equals() los objetos que están en ese cubo. Si dos objetos iguales tienen hashes distintos, nunca se llegan a comparar.

**¿Y si pongo siempre hashCode() devolviendo 1?** Cumple el contrato, pero todos los elementos caerían en el mismo cubo y el HashSet se volvería lento, casi tan lento como recorrer una lista. El hash bueno reparte.

**¿Qué campos uso para equals() y hashCode()? Los que identifican** al objeto. Para un libro, el ISBN; para una persona, quizá el DNI. Y los mismos en los dos métodos. Objects.hash(...) y Objects.equals(...) te ayudan a escribirlos sin preocuparte de los null.

¿Cómo evito lo de la clave que cambia? Usa claves inmutables: campos final y sin setters. Un record, un String o un Integer son buenos candidatos precisamente por eso.

Sobrescribir equals() y olvidar hashCode(). Compila sin avisos, pasa las pruebas con un solo objeto y falla cuando hay dos «iguales» en un HashSet o un HashMap.

Pruébalo tú

  1. Añade a LibroCompleto un segundo campo titulo que no entre en equals() ni en hashCode(). Comprueba que dos libros con el mismo ISBN y distinto título siguen siendo el mismo.
  2. Cambia LibroRecord para que tenga dos campos (isbn y titulo) y comprueba que ahora dos libros con el mismo ISBN y distinto título no son iguales. ¿Por qué?

Programa 3: colas y pilas de préstamos

La biblioteca también tiene colas: de personas que esperan, de libros que se devuelven y de reservas con prioridad. Tres estructuras, tres comportamientos.

La idea

  • Una cola (FIFO, first in, first out): el primero que llega es el primero en salir. Es la cola de socios que esperan atención.
  • Una pila (LIFO, last in, first out): el último que entra es el primero en salir. Es el carrito de libros devueltos: el que dejaste encima es el que recoges primero.
  • Una cola de prioridad: no importa quién llegó antes, sale primero el más urgente. Para saber qué es «más urgente», Reserva implementa Comparable (lo viste en la teoría de Comparable).

Tanto la cola como la pila las hacemos con el mismo tipo, ArrayDeque, que es una cola de doble extremo (double ended queue). Usa unos métodos u otros según la quieras como cola o como pila.

push y pop actúan por el principio de la estructura; offer añade por el final y poll saca por el principio. Por eso push+pop se comportan como una pila y offer+poll como una cola.

El código

Cola.java

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.NoSuchElementException;
import java.util.PriorityQueue;

public class Cola {

    record Reserva(String socio, int prioridad) implements Comparable<Reserva> {
        @Override
        public int compareTo(Reserva otra) {
            return Integer.compare(prioridad, otra.prioridad);   // menor número = más urgente
        }
    }

    public static void main(String[] args) {
        // 1. Cola (FIFO): el primero en llegar es el primero en salir
        Deque<String> espera = new ArrayDeque<>();
        espera.offer("Ana");
        espera.offer("Luis");
        espera.offer("Marta");
        System.out.println("Cola: " + espera);
        System.out.println("Quién va primero (peek): " + espera.peek());
        System.out.println("Atiendo a (poll): " + espera.poll());
        System.out.println("Cola ahora: " + espera);

        // 2. Pila (LIFO): el último en llegar es el primero en salir
        Deque<String> devueltos = new ArrayDeque<>();
        devueltos.push("Dune");
        devueltos.push("Emma");
        devueltos.push("Hamlet");
        System.out.println("Pila: " + devueltos);
        System.out.println("Cima (peek): " + devueltos.peek());
        System.out.println("Recoloco (pop): " + devueltos.pop());
        System.out.println("Pila ahora: " + devueltos);

        // 3. Cola de prioridad: sale primero el "menor" según compareTo
        PriorityQueue<Reserva> reservas = new PriorityQueue<>();
        reservas.add(new Reserva("Pablo", 3));
        reservas.add(new Reserva("Lucía", 1));
        reservas.add(new Reserva("Irene", 2));
        reservas.add(new Reserva("Mario", 5));
        System.out.println("Imprimirla no la ordena: " + reservas);
        System.out.println("Orden de atención:");
        while (!reservas.isEmpty()) {
            System.out.println("  " + reservas.poll());
        }

        // 4. Colas y pilas vacías
        Deque<String> vacia = new ArrayDeque<>();
        System.out.println("poll() en una cola vacía: " + vacia.poll());
        try {
            vacia.pop();
        } catch (NoSuchElementException e) {
            System.out.println("pop() en una pila vacía: " + e.getClass().getSimpleName());
        }
    }
}

Salida

Cola: [Ana, Luis, Marta]
Quién va primero (peek): Ana
Atiendo a (poll): Ana
Cola ahora: [Luis, Marta]
Pila: [Hamlet, Emma, Dune]
Cima (peek): Hamlet
Recoloco (pop): Hamlet
Pila ahora: [Emma, Dune]
Imprimirla no la ordena: [Reserva[socio=Lucía, prioridad=1], Reserva[socio=Pablo, prioridad=3], Reserva[socio=Irene, prioridad=2], Reserva[socio=Mario, prioridad=5]]
Orden de atención:
  Reserva[socio=Lucía, prioridad=1]
  Reserva[socio=Irene, prioridad=2]
  Reserva[socio=Pablo, prioridad=3]
  Reserva[socio=Mario, prioridad=5]
poll() en una cola vacía: null
pop() en una pila vacía: NoSuchElementException

Compruébalo a mano:

  • Cola: Ana, Luis, Marta entran en ese orden; peek() la mira sin sacarla, poll() la saca y la cola queda [Luis, Marta].
  • Pila: Dune, Emma, Hamlet entran en ese orden, pero la pila se imprime con Hamlet delante (la cima). pop() devuelve Hamlet, el último que entró.
  • Cola de prioridad: al imprimirla, no sale ordenada (Pablo con prioridad 3 aparece antes que Irene con 2). Solo se garantiza que el primero sea el menor. Pero al sacar con poll() sale todo en orden: 1, 2, 3, 5.
  • Vacías: poll() en una cola vacía da null; pop() en una pila vacía lanza NoSuchElementException.

Hay una clase antigua, Stack, que también funciona como pila, pero la recomendación actual es usar ArrayDeque para pilas y colas. Stack arrastra diseños de la primera versión de Java.

Preguntas que te puedes hacer

**¿Por qué peek() y poll() devuelven null y no una excepción?** Porque están pensados para el caso normal «puede que no haya nadie». Existen sus versiones que lanzan excepción (element() y remove()) para cuando una cola vacía sea un error. pop(), en cambio, sí lanza excepción.

¿Qué pasa si dos reservas tienen la misma prioridad? El orden entre ellas no está garantizado. Si el empate importa, añade un segundo criterio a compareTo (por ejemplo, la hora de llegada).

**¿Por qué una PriorityQueue no se imprime ordenada?* Por dentro es un montículo (*heap): una estructura que solo garantiza que el menor está al principio, no que todo esté ordenado. Si quieres recorrerla en orden, tienes que ir sacando con poll().

**¿Puedo recorrer una cola con for-each?** Sí, pero en el orden interno de la estructura (el que imprime). Para ArrayDeque es el esperado; para PriorityQueue, no.

Confundir add/offer con push. Si metes con add y sacas con pop, mezclas el final con el principio y el orden sale al revés de lo que esperabas.

Pruébalo tú

  1. Cambia Reserva para que, a igualdad de prioridad, se atienda primero al socio cuyo nombre sea alfabéticamente menor. Pista: compareTo con dos criterios.
  2. Haz que la cola de espera sea de prioridad con una PriorityQueue<String> y comprueba en qué orden atiende a Ana, Luis y Marta. ¿Por qué ese orden?

Errores típicos en esta práctica

  • Esperar un orden de un HashMap o HashSet: no hay ninguno garantizado. Usa LinkedHash... o Tree....
  • Hacer mapa.put(p, mapa.get(p) + 1) sin comprobar si existe: NullPointerException la primera vez. Usa merge o getOrDefault.
  • Sobrescribir solo equals() (o solo hashCode()): el HashSet y el HashMap se portan mal sin avisar.
  • Cambiar un campo que forma parte del hash de un objeto que ya está dentro de un HashSet o un HashMap: se pierde sin error.
  • Mezclar los métodos de cola y de pila (add con pop): el orden sale invertido.
  • Esperar que una PriorityQueue se imprima ordenada: solo poll() entrega en orden.

Míralo paso a paso en Python Tutor

Python Tutor ejecuta el código línea a línea y dibuja variables, arrays y referencias. Elige Java. Aquí tienes cómo trabaja por dentro un ArrayDeque: un array circular con un índice de cabeza, donde sacar el primero no obliga a mover a nadie.

public class Tutor {
    public static void main(String[] args) {
        String[] cola = new String[4];
        int cabeza = 0;
        int cuantos = 0;

        String[] llegan = {"Ana", "Luis", "Marta"};
        for (String s : llegan) {                          // offer() de tres personas
            cola[(cabeza + cuantos) % cola.length] = s;
            cuantos++;
        }

        String atendido = cola[cabeza];                    // poll(): sale el primero
        cola[cabeza] = null;
        cabeza = (cabeza + 1) % cola.length;
        cuantos--;

        cola[(cabeza + cuantos) % cola.length] = "Pablo";  // offer(): ocupa el último hueco
        cuantos++;
        cola[(cabeza + cuantos) % cola.length] = "Irene";  // offer(): vuelve al principio
        cuantos++;

        System.out.println(atendido + " ya está atendido");
        for (int i = 0; i < cuantos; i++) {
            System.out.println(cola[(cabeza + i) % cola.length]);
        }
    }
}

Salida esperada:

Ana ya está atendido
Luis
Marta
Pablo
Irene

Qué observar paso a paso:

  1. Tras el primer for, cola tiene Ana, Luis, Marta y un hueco (null) al final. cabeza vale 0 y cuantos, 3.
  2. En el «poll», atendido recibe "Ana", su hueco pasa a null y cabeza avanza a 1. Nadie se ha movido: Luis y Marta siguen exactamente en las mismas posiciones del array.
  3. Pablo se guarda en (1 + 2) % 4 = 3, el último hueco del array.
  4. Irene se guarda en (1 + 3) % 4 = 0: el índice da la vuelta y reutiliza el hueco que dejó Ana. El array queda [Irene, Luis, Marta, Pablo], pero el orden real de la cola, que lee a partir de cabeza, es Luis, Marta, Pablo, Irene.

Resumen

  • Map asocia claves con valores; merge(clave, 1, Integer::sum) es la forma corta de contar, y getOrDefault la explícita.
  • HashMap no promete orden; LinkedHashMap respeta la inserción y TreeMap ordena por clave.
  • HashSet y HashMap exigen equals() y hashCode() coherentes en las claves: el hash elige el cubo y equals decide. Con solo uno de los dos, aparecen repetidos.
  • Las claves deben ser inmutables: si cambias lo que entra en el hash, el elemento «desaparece» de las búsquedas.
  • ArrayDeque sirve como cola (offer/poll) y como pila (push/pop); PriorityQueue saca siempre el menor según Comparable (o un Comparator).

Checklist: ¿lo has practicado?

  • [ ] He compilado y ejecutado los tres programas.
  • [ ] He comprobado a mano al menos una salida de cada programa.
  • [ ] He visto que HashMap, TreeMap y LinkedHashMap imprimen en órdenes distintos.
  • [ ] He reproducido el caso de «solo equals» y entiendo por qué el conjunto da 2.
  • [ ] He visto que una clave que cambia deja de encontrarse.
  • [ ] He comprobado que una PriorityQueue impresa no sale ordenada, pero poll() sí.
  • [ ] He mirado el programa de Python Tutor y he visto cómo el índice da la vuelta al array.

Y ahora, a por los ejercicios: ejercicios de colecciones, con tres niveles, tres fragmentos para depurar y un chuletario al final. ¡Nos vemos allí!

Siguiente paso: ejerciciosColecciones en Java — ejercicios con autores, catálogos y una fusión de bibliotecas (y la «b» que estaba en el mapa pero no aparecía)

¿Te ha servido este artículo? Así puedes apoyar SergioLearns →

Sigue aprendiendo

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *