Tema 8 • Resumen del tema Colecciones y TAD

Resumen del Tema 8: Colecciones y Tipos Abstractos de Datos

En este tema damos un paso enorme en la estructuración de la información. Pasamos de usar simples arrays a utilizar el Java Collections Framework (JCF), un conjunto de herramientas muy potente para manejar grupos de objetos de forma eficiente.

1. Tipos Abstractos de Datos (TAD)

Un TAD es un modelo definido para representar tipos abstractos (como una pila o un conjunto) creando un nuevo tipo de dato más avanzado[cite: 2847]. Se especifican mediante una interfaz y se definen mediante la implementación de esas interfaces[cite: 2860, 2861]. Algunos ejemplos clásicos son:

  • Pilas (Stack): Colección de elementos que sigue la propiedad LIFO (Last In, First Out)[cite: 2870].
  • Colas (Queue): Colección que sigue la propiedad FIFO (First In, First Out)[cite: 2871].
  • Conjuntos (Set): Colección sin elementos duplicados[cite: 2872].
  • Diccionarios (Map): Conjunto de asociaciones de clave y valor[cite: 2874].

2. Java Collections Framework: Jerarquía

Las colecciones en Java están dentro del paquete java.util.*[cite: 2964]. La estructura principal se divide en dos grandes ramas:

  1. Collection: Es la interfaz raíz de la que heredan List, Set y Queue[cite: 2941, 2942].
  2. Map: Es una interfaz independiente que representa diccionarios clave-valor[cite: 2938].

3. Interfaz Set (Conjuntos)

Los Set implementan conjuntos de elementos donde no se permiten duplicados[cite: 3000, 3003]. Sus implementaciones más comunes son:

  • HashSet: Almacena los elementos en una tabla hash. Su acceso es muy rápido $(O(1))$, pero no garantiza ningún orden[cite: 3031, 3032, 3338].
  • LinkedHashSet: Similar al HashSet, pero los elementos se ordenan por su orden de inserción[cite: 3219].
  • TreeSet: Utiliza una estructura de árbol binario. Mantiene los elementos ordenados de forma ascendente (orden natural) pero es ligeramente más lento $(O(\log n))$[cite: 3295, 3296, 3338].

4. Interfaz List (Listas)

Las listas permiten el acceso a los elementos por su posición (índice), permiten duplicados y mantienen el orden de inserción[cite: 3521, 3522, 3523].

Característica ArrayList LinkedList
Estructura interna Array dinámico en memoria contigua[cite: 3549]. Lista doblemente enlazada mediante nodos[cite: 3665].
Acceso por índice get(i) Muy rápido $(O(1))$[cite: 3740]. Más lento $(O(n))$[cite: 3740].
Inserción en medio Lenta (requiere mover elementos)[cite: 3740]. Rápida (sólo se ajustan los enlaces)[cite: 3740].

5. Interfaz Map (Diccionarios)

Asocia pares de valores (clave-valor). Las claves no se pueden repetir, pero los valores sí[cite: 3802, 3813, 3814]. Es ideal para casos como configuraciones de aplicaciones o gestión de inventarios[cite: 3826, 3832].

  • HashMap: Operaciones rápidas $(O(1))$, no garantiza orden[cite: 3905].
  • LinkedHashMap: Mantiene el orden de inserción combinando una tabla hash con una lista enlazada[cite: 3909, 3966].
  • TreeMap: Ordena las claves de forma natural o según un comparador personalizado[cite: 3907].

6. Tipos Genéricos y Wrappers

Los tipos genéricos <T> permiten crear colecciones que operan con tipos de datos específicos, mejorando la seguridad del código y evitando errores en tiempo de ejecución[cite: 3077, 3078].

Las colecciones no admiten tipos primitivos (como int o double). Para usarlos, debemos emplear las clases envoltorio (Wrappers) como Integer o Double[cite: 3143, 3144]. Java realiza el autoboxing y unboxing automáticamente para convertir entre primitivos y sus objetos correspondientes[cite: 3109, 3111].

7. Ordenación: Comparable, Comparator y Collections

Para ordenar colecciones, Java nos proporciona dos interfaces clave:

  • Comparable: Se implementa en la propia clase (ej: Persona) sobrescribiendo el método compareTo(T o) para definir el orden natural del objeto[cite: 3356, 3359]. Si se sobrescribe, debe tener concordancia con el método equals()[cite: 3366, 3380].
  • Comparator: Se crea en clases aparte para establecer órdenes alternativos sobrescribiendo el método compare(T o1, T o2)[cite: 3400, 3415]. Muy útil con funciones lambda: Comparator.comparing(Persona::getNombre)[cite: 3449].

Además, disponemos de la clase de utilidades Collections que ofrece métodos estáticos muy útiles como sort(), reverse(), shuffle(), max() o min()[cite: 4073, 4079, 4081].