Implementación de Estructuras de Datos y Modelado de Objetos en Java

Clasificado en Informática

Escrito el en español con un tamaño de 28,47 KB

Ejercicios Prácticos de Java: Collections y Programación Orientada a Objetos

Este documento presenta una serie de ejercicios prácticos en Java, cubriendo la implementación y el uso de diversas estructuras de datos de la API de Collections, así como conceptos avanzados de Programación Orientada a Objetos (POO) como el manejo de excepciones y el modelado de relaciones entre objetos.


1. Implementación de ArrayList: Métodos de Collection y List

En esta sección, exploraremos los métodos más comunes de las interfaces Collection y List utilizando una implementación concreta: ArrayList de Integer.

Métodos de la Interfaz Collection

  • boolean add(E e)

    Añade un elemento E a la colección. Retorna true si la colección cambió como resultado de la llamada.

  • void clear()

    Elimina todos los elementos de la colección.

  • boolean contains(Object o)

    Retorna true si la colección contiene el elemento especificado.

  • boolean isEmpty()

    Retorna true si la colección no contiene elementos.

  • boolean remove(Object o)

    Elimina una única instancia del elemento especificado de esta colección, si está presente.

  • int size()

    Devuelve el número de elementos en la colección.

  • <T> T[] toArray(T[] a)

    Devuelve un array que contiene todos los elementos de la colección en el orden correcto.

Métodos de la Interfaz List

  • void add(int index, E element)

    Inserta el elemento especificado en la posición indicada en la lista. Desplaza los elementos subsiguientes a la derecha.

  • E get(int index)

    Devuelve el elemento en la posición especificada en la lista.

  • E remove(int index)

    Elimina el elemento en la posición especificada en la lista. Los elementos adyacentes a la derecha se desplazarán hacia la izquierda.

  • E set(int index, E element)

    Reemplaza el elemento en la posición especificada en la lista con el elemento especificado.

Clase Principal: MainLista1

import java.util.ArrayList;
import java.util.List;

public class MainLista1 {
    public static void main(String[] args) {
        // Crear un ArrayList de Integer
        List<Integer> lista = new ArrayList<>();

        // Método add(E e) - Añadir elementos a la lista
        lista.add(10);
        lista.add(20);
        lista.add(30);
        System.out.println("Lista después de añadir elementos: " + lista);

        // Método contains(Object o) - Verificar si un elemento está en la lista
        System.out.println("¿La lista contiene 20? " + lista.contains(20));

        // Método isEmpty() - Verificar si la lista está vacía
        System.out.println("¿La lista está vacía? " + lista.isEmpty());

        // Método size() - Obtener el tamaño de la lista
        System.out.println("Tamaño de la lista: " + lista.size());

        // Método toArray(T[] a) - Convertir la lista en un array
        Integer[] array = lista.toArray(new Integer[0]);
        System.out.print("Elementos del array: ");
        for (int num : array) {
            System.out.print(num + " ");
        }
        System.out.println();

        // Método add(int index, E element) - Insertar un elemento en una posición específica
        lista.add(1, 15);
        System.out.println("Lista después de insertar 15 en la posición 1: " + lista);

        // Método get(int index) - Obtener un elemento en una posición específica
        System.out.println("Elemento en la posición 2: " + lista.get(2));

        // Método remove(int index) - Eliminar un elemento en una posición específica
        lista.remove(2);
        System.out.println("Lista después de eliminar el elemento en la posición 2: " + lista);

        // Método remove(Object o) - Eliminar un elemento si existe en la lista
        lista.remove(Integer.valueOf(10));
        System.out.println("Lista después de eliminar el 10: " + lista);

        // Método set(int index, E element) - Reemplazar un elemento en una posición específica
        lista.set(0, 50);
        System.out.println("Lista después de reemplazar el primer elemento por 50: " + lista);

        // Método clear() - Vaciar la lista
        lista.clear();
        System.out.println("Lista después de usar clear(): " + lista);

        // Verificar si la lista está vacía después de clear()
        System.out.println("¿La lista está vacía después de clear()? " + lista.isEmpty());
    }
}

2. Uso de la Clase Stack en Java: Implementación de una Pila

En este ejercicio, implementaremos una pila de enteros utilizando la clase Stack de Java y exploraremos sus métodos principales.

Métodos Principales de Stack

  • boolean empty()

    Comprueba si esta pila está vacía.

  • E peek()

    Examina el objeto en la cima de esta pila sin eliminarlo.

  • E pop()

    Elimina el objeto en la cima de esta pila y lo devuelve como el valor de esta función.

  • E push(E item)

    Apila un elemento en la cima de esta pila.

  • int search(Object o)

    Devuelve la posición (basada en 1) donde un objeto se encuentra en esta pila.

Clase Principal: MainPila1

import java.util.Stack; // Importamos la clase Stack

public class MainPila1 {
    public static void main(String[] args) {
        // Creamos una pila de enteros
        Stack<Integer> pila = new Stack<>();

        // Verificamos si la pila está vacía (debería ser true al inicio)
        System.out.println("¿La pila está vacía? " + pila.empty());

        // Apilamos (push) elementos en la pila
        pila.push(10);
        pila.push(20);
        pila.push(30);
        System.out.println("Pila después de apilar 10, 20 y 30: " + pila);

        // Obtenemos el elemento en la cima sin eliminarlo (peek)
        System.out.println("Elemento en la cima: " + pila.peek());

        // Desapilamos (pop) el elemento superior
        System.out.println("Elemento eliminado: " + pila.pop());
        System.out.println("Pila después de desapilar: " + pila);

        // Buscamos la posición de un elemento en la pila (índice basado en 1)
        System.out.println("Posición de 10 en la pila: " + pila.search(10));
        System.out.println("Posición de 20 en la pila: " + pila.search(20));
        System.out.println("Posición de 30 en la pila (ya eliminado): " + pila.search(30));
    }
}

3. Implementación de una Cola con LinkedList y la Interfaz Queue

En este ejercicio, implementaremos una cola de enteros utilizando la clase LinkedList, pero restringiéndonos a los métodos definidos en la interfaz Queue.

Métodos Principales de Queue

  • boolean add(E e)

    Inserta el elemento especificado en esta cola si es posible hacerlo inmediatamente sin violar las restricciones de capacidad, devolviendo true si tiene éxito y lanzando una IllegalStateException si no hay espacio disponible.

  • E element()

    Recupera, pero no elimina, la cabeza de esta cola. Lanza una NoSuchElementException si la cola está vacía.

  • boolean offer(E e)

    Inserta el elemento especificado en esta cola si es posible hacerlo inmediatamente sin violar las restricciones de capacidad. Retorna true si tiene éxito, false si no hay espacio disponible.

  • E peek()

    Recupera, pero no elimina, la cabeza de esta cola, o retorna null si esta cola está vacía.

  • E poll()

    Recupera y elimina la cabeza de esta cola, o retorna null si esta cola está vacía.

  • E remove()

    Recupera y elimina la cabeza de esta cola. Lanza una NoSuchElementException si la cola está vacía.

Clase Principal: MainCola1

import java.util.LinkedList;
import java.util.Queue;

public class MainCola1 {
    public static void main(String[] args) {
        // Se crea una cola de enteros usando LinkedList
        Queue<Integer> cola = new LinkedList<>();

        // Agrega elementos a la cola usando add (lanza excepción si falla)
        cola.add(10);
        cola.add(20);
        cola.add(30);
        System.out.println("Cola después de add: " + cola);

        // Agrega elementos a la cola usando offer (retorna false si falla)
        cola.offer(40);
        cola.offer(50);
        System.out.println("Cola después de offer: " + cola);

        // Obtiene el primer elemento sin eliminarlo usando element (lanza excepción si está vacía)
        System.out.println("Primer elemento con element(): " + cola.element());

        // Obtiene el primer elemento sin eliminarlo usando peek (retorna null si está vacía)
        System.out.println("Primer elemento con peek(): " + cola.peek());

        // Obtiene y elimina el primer elemento usando poll (retorna null si está vacía)
        System.out.println("Elemento eliminado con poll(): " + cola.poll());
        System.out.println("Cola después de poll: " + cola);

        // Obtiene y elimina el primer elemento usando remove (lanza excepción si está vacía)
        System.out.println("Elemento eliminado con remove(): " + cola.remove());
        System.out.println("Cola después de remove: " + cola);
    }
}

4. Simulación de Cola de Cine con LinkedList en Java

Este ejercicio simula una cola de cine donde, además de las operaciones básicas de encolar y desencolar, se permite añadir o quitar personas en cualquier posición de la cola, aprovechando la flexibilidad de LinkedList.

Clase Principal: MainColaCine1

import java.util.LinkedList;
import java.util.Scanner;

// Clase principal que maneja la simulación de la cola en el cine
public class MainColaCine1 {
    public static void main(String[] args) {
        LinkedList<String> colaCine = new LinkedList<>(); // Lista enlazada para simular la cola
        Scanner scanner = new Scanner(System.in);
        int opcion;

        do {
            // Menú de opciones
            System.out.println("\n--- SIMULACIÓN DE COLA DE CINE ---");
            System.out.println("1. Encolar persona");
            System.out.println("2. Desencolar persona");
            System.out.println("3. Añadir persona en posición específica");
            System.out.println("4. Quitar persona en posición específica");
            System.out.println("5. Mostrar cola");
            System.out.println("6. Salir");
            System.out.print("Elige una opción: ");
            opcion = scanner.nextInt();
            scanner.nextLine(); // Limpiar buffer

            switch (opcion) {
                case 1:
                    // Añadir persona al final de la cola
                    System.out.print("Ingrese el nombre de la persona: ");
                    String persona = scanner.nextLine();
                    colaCine.addLast(persona);
                    System.out.println(persona + " ha sido añadida a la cola.");
                    break;
                case 2:
                    // Quitar persona del inicio de la cola
                    if (!colaCine.isEmpty()) {
                        System.out.println(colaCine.removeFirst() + " ha salido de la cola.");
                    } else {
                        System.out.println("La cola está vacía.");
                    }
                    break;
                case 3:
                    // Insertar persona en una posición específica
                    System.out.print("Ingrese el nombre de la persona: ");
                    String nuevaPersona = scanner.nextLine();
                    System.out.print("Ingrese la posición (0 para inicio): ");
                    int posicion = scanner.nextInt();
                    scanner.nextLine();
                    if (posicion >= 0 && posicion <= colaCine.size()) {
                        colaCine.add(posicion, nuevaPersona);
                        System.out.println(nuevaPersona + " ha sido añadida en la posición " + posicion);
                    } else {
                        System.out.println("Posición inválida.");
                    }
                    break;
                case 4:
                    // Eliminar persona de una posición específica
                    System.out.print("Ingrese la posición de la persona a eliminar: ");
                    int posEliminar = scanner.nextInt();
                    scanner.nextLine();
                    if (posEliminar >= 0 && posEliminar < colaCine.size()) {
                        System.out.println(colaCine.remove(posEliminar) + " ha sido eliminada de la cola.");
                    } else {
                        System.out.println("Posición inválida.");
                    }
                    break;
                case 5:
                    // Mostrar la cola actual
                    System.out.println("Cola actual: " + colaCine);
                    break;
                case 6:
                    // Salir del programa
                    System.out.println("Saliendo del programa...");
                    break;
                default:
                    System.out.println("Opción inválida, intenta de nuevo.");
            }
        } while (opcion != 6);
        scanner.close();
    }
}

5. Modelado de Relaciones y Excepciones: El Caso Rubiales

Este ejercicio propone un escenario para modelar interacciones entre personas, incluyendo relaciones de pareja y el manejo de solicitudes de besos, con un enfoque en la gestión de excepciones para situaciones no consentidas.

Descripción del Escenario

Cierto día hubo polémica porque una jugadora de fútbol (Jenni) recibió un beso no consentido de una persona llamada “Rubiales”. Supongamos que:

  • Toda persona tiene un nombre y puede tener una pareja.
  • Jenni tiene una pareja llamada “X”.
  • Toda persona, además, puede recibir una solicitud de beso por la vía formal o por la vía informal (sin permiso). En este caso, la persona se siente ofendida y generará una excepción.
  • Toda persona que solicite dar un beso a otra por la vía formal tendrá éxito si y solo si: es la pareja, a la persona le apetece recibir besos y está contenta.
  • Toda persona tiene, por tanto, los siguientes atributos: nombre, pareja, leApeteceBeso (por defecto false) y estaContenta. La clase Persona debe tener todos los getters y setters.

Requisitos de Implementación

  • Crea la clase Persona con los atributos y constructores necesarios.
  • Añade un método para recibir besos, tanto formales como informales: boolean solicitudBeso(boolean maneraFormal, Persona persona), donde maneraFormal indica si la solicitud es formal o no, y persona es la persona que pretende dar el beso.
  • El método devolverá true si se ha producido el beso (es la pareja, quiere y está contenta).
  • El método producirá una excepción siempre que la solicitud sea informal y la persona solicitante no sea la pareja del objeto que recibe el mensaje.

En el Método Principal (main):

  • Crea a Jenni (nombre “Jenni”), le apetece recibir un beso y, además, está contenta.
  • Crea a X (nombre “X”).
  • Crea a “Rubiales”.
  • Asocia X como pareja de Jenni y Jenni como pareja de X.
  • X ejecutará una solicitud de método formal a Jenni (habrá éxito, devolviendo true).
  • Rubiales ejecutará una solicitud de método informal (no habrá éxito y se producirá una excepción).
  • Rubiales ejecutará una solicitud de método formal (no habrá éxito, devolviendo false).
  • Jenni ahora no le apetece recibir besos.
  • X ejecutará una solicitud de método formal a Jenni (no habrá éxito, devolviendo false, pero no se producirá una excepción puesto que es su pareja).

Clases: Persona y CasoRubiales

// Definición de la clase Persona
class Persona {
    private String nombre; // Nombre de la persona
    private Persona pareja; // Pareja de la persona
    private boolean leApeteceBeso; // Indica si le apetece recibir un beso
    private boolean estaContenta; // Indica si está contenta

    // Constructor de la clase
    public Persona(String nombre) {
        this.nombre = nombre;
        this.pareja = null;
        this.leApeteceBeso = false;
        this.estaContenta = false;
    }

    // Getters y Setters
    public String getNombre() {
        return nombre;
    }

    public void setPareja(Persona pareja) {
        this.pareja = pareja;
    }

    public Persona getPareja() {
        return pareja;
    }

    public boolean isLeApeteceBeso() {
        return leApeteceBeso;
    }

    public void setLeApeteceBeso(boolean leApeteceBeso) {
        this.leApeteceBeso = leApeteceBeso;
    }

    public boolean isEstaContenta() {
        return estaContenta;
    }

    public void setEstaContenta(boolean estaContenta) {
        this.estaContenta = estaContenta;
    }

    // Método para solicitar un beso
    public boolean solicitudBeso(boolean maneraFormal, Persona persona) throws Exception {
        if (!maneraFormal && persona != pareja) {
            // Si la solicitud es informal y no es la pareja, lanza una excepción
            throw new Exception(nombre + " se siente ofendida por la solicitud de " + persona.getNombre());
        }
        // Si la solicitud es formal, se evalúan las condiciones para aceptar el beso
        if (persona == pareja && leApeteceBeso && estaContenta) {
            return true; // El beso se produce
        }
        return false; // No se cumplen las condiciones, el beso no se da
    }
}

// Clase principal
public class CasoRubiales {
    public static void main(String[] args) {
        try {
            // Creación de los personajes
            Persona jenny = new Persona("Jenni");
            Persona x = new Persona("X");
            Persona rubiales = new Persona("Rubiales");

            // Configuración de la relación de pareja
            jenny.setPareja(x);
            x.setPareja(jenny);

            // Jenni está contenta y le apetece recibir besos
            jenny.setLeApeteceBeso(true);
            jenny.setEstaContenta(true);

            // X solicita un beso formal a Jenni (debería ser exitoso)
            System.out.println("X solicita un beso formal a Jenni: " + jenny.solicitudBeso(true, x));

            // Rubiales solicita un beso informal a Jenni (debería lanzar una excepción)
            try {
                System.out.println("Rubiales solicita un beso informal a Jenni: " + jenny.solicitudBeso(false, rubiales));
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }

            // Rubiales solicita un beso formal a Jenni (debería fallar y devolver false)
            System.out.println("Rubiales solicita un beso formal a Jenni: " + jenny.solicitudBeso(true, rubiales));

            // Jenni ya no quiere recibir besos
            jenny.setLeApeteceBeso(false);

            // X solicita un beso formal a Jenni nuevamente (debería fallar y devolver false)
            System.out.println("X solicita un beso formal a Jenni después del cambio: " + jenny.solicitudBeso(true, x));
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

6. Sistema de Búsqueda de Parejas Basado en Características con Java Collections

Continuando con el modelado de personas, este ejercicio se enfoca en definir características personales y preferencias para encontrar posibles parejas. Se utilizarán colecciones para gestionar las características propias y deseables de cada individuo.

Descripción del Escenario

Se pretende reflejar qué características tiene una persona (por ejemplo: curioso/a, friki, amable, le gusta la fotografía, le gusta la Programación) y qué características busca en una pareja. Para ello, se fijará en las características propias de las personas y, en el caso de que cumpla todos los requisitos, esta podría estar interesada en esas personas, pero no tiene por qué ser a la inversa.

Por ejemplo, dadas dos personas p1 y p2 y las características c1, c2, c3, c4 y c5, la relación entre ellas podría ser la siguiente:

Persona       Tiene         Desea
------------------------------
p1            c4, c5        c2, c4
p2            c1, c3, c4    c5
p3            c2, c5        c4

Con estos datos, podremos sacar las siguientes conclusiones:

  • p1 no podría tener ninguna pareja porque no hay nadie que tenga esas características.
  • p2 observa que las personas p1 y p3 tienen características deseables.
  • p3 observa que las personas p1 y p2 tienen características deseables.
  • La única pareja posible es p2 y p3 (si la relación es bidireccional).

Requisitos de Implementación

  • Modele la clase Persona y Caracteristica, permitiendo que Persona tenga una colección de características propias y una colección de características deseables. Escoja el tipo de colección que considere adecuado (Set es ideal para características únicas). Tenga en cuenta que una característica tiene, como atributo, la descripción de dicha característica.
  • Cree las personas y características de la tabla anterior (en este caso, c1, c2...c5 son descripciones de las características).
  • Recorra las personas indicando, para cada una de ellas, las características propias y deseables.
  • Recorra las personas indicando qué personas cumplen las características deseables de otra.
  • Indique qué personas podrían ser pareja (cumplen todos los requisitos de características deseables mutuamente).

Clases: Caracteristica, Persona y MainParejas1

import java.util.*;

// Clase que representa una característica
class Caracteristica {
    private String descripcion; // Descripción de la característica

    public Caracteristica(String descripcion) {
        this.descripcion = descripcion;
    }

    public String getDescripcion() {
        return descripcion;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Caracteristica that = (Caracteristica) obj;
        return Objects.equals(descripcion, that.descripcion);
    }

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

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

// Clase que representa una persona
class Persona {
    private String nombre; // Nombre de la persona
    private Set<Caracteristica> caracteristicasPropias; // Características que posee
    private Set<Caracteristica> caracteristicasDeseadas; // Características deseadas en una pareja

    public Persona(String nombre) {
        this.nombre = nombre;
        this.caracteristicasPropias = new HashSet<>();
        this.caracteristicasDeseadas = new HashSet<>();
    }

    public String getNombre() {
        return nombre;
    }

    public void agregarCaracteristicaPropia(Caracteristica c) {
        caracteristicasPropias.add(c);
    }

    public void agregarCaracteristicaDeseada(Caracteristica c) {
        caracteristicasDeseadas.add(c);
    }

    public Set<Caracteristica> getCaracteristicasPropias() {
        return caracteristicasPropias;
    }

    public Set<Caracteristica> getCaracteristicasDeseadas() {
        return caracteristicasDeseadas;
    }

    // Método que verifica si 'otra' persona cumple con las características deseadas por esta persona
    public boolean cumpleRequisitos(Persona otra) {
        return otra.getCaracteristicasPropias().containsAll(caracteristicasDeseadas);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Persona persona = (Persona) o;
        return Objects.equals(nombre, persona.nombre);
    }

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

// Clase principal
public class MainParejas1 {
    public static void main(String[] args) {
        // Creación de características
        Caracteristica c1 = new Caracteristica("Curioso");
        Caracteristica c2 = new Caracteristica("Friki");
        Caracteristica c3 = new Caracteristica("Amable");
        Caracteristica c4 = new Caracteristica("Le gusta la fotografía");
        Caracteristica c5 = new Caracteristica("Le gusta Programación");

        // Creación de personas
        Persona p1 = new Persona("P1");
        Persona p2 = new Persona("P2");
        Persona p3 = new Persona("P3");

        // Asignación de características propias
        p1.agregarCaracteristicaPropia(c4);
        p1.agregarCaracteristicaPropia(c5);

        p2.agregarCaracteristicaPropia(c1);
        p2.agregarCaracteristicaPropia(c3);
        p2.agregarCaracteristicaPropia(c4);

        p3.agregarCaracteristicaPropia(c2);
        p3.agregarCaracteristicaPropia(c5);

        // Asignación de características deseadas en una pareja
        p1.agregarCaracteristicaDeseada(c2);
        p1.agregarCaracteristicaDeseada(c4);

        p2.agregarCaracteristicaDeseada(c5);

        p3.agregarCaracteristicaDeseada(c4);

        List<Persona> todasLasPersonas = Arrays.asList(p1, p2, p3);

        // Mostrar características de cada persona
        System.out.println("--- Características de cada persona ---");
        for (Persona p : todasLasPersonas) {
            System.out.println(p.getNombre() + " tiene: " + p.getCaracteristicasPropias());
            System.out.println(p.getNombre() + " desea: " + p.getCaracteristicasDeseadas());
            System.out.println();
        }

        // Recorrer las personas indicando qué personas cumplen las características deseables
        System.out.println("--- Personas que cumplen las características deseadas por otra ---");
        for (Persona p : todasLasPersonas) {
            for (Persona otra : todasLasPersonas) {
                if (!p.equals(otra) && p.cumpleRequisitos(otra)) {
                    System.out.println(otra.getNombre() + " cumple las características deseadas por " + p.getNombre());
                }
            }
        }
        System.out.println();

        // Indicar qué personas podrían ser pareja (cumplen todos los requisitos de características deseables mutuamente)
        System.out.println("--- Posibles parejas (cumplimiento mutuo de requisitos) ---");
        Set<String> parejasEncontradas = new HashSet<>(); // Para evitar duplicados (p1-p2 y p2-p1)
        for (Persona pA : todasLasPersonas) {
            for (Persona pB : todasLasPersonas) {
                if (!pA.equals(pB) && pA.cumpleRequisitos(pB) && pB.cumpleRequisitos(pA)) {
                    // Formar una clave única para la pareja (ej. "P1-P2" o "P2-P1")
                    String parejaKey1 = pA.getNombre() + "-" + pB.getNombre();
                    String parejaKey2 = pB.getNombre() + "-" + pA.getNombre();

                    if (!parejasEncontradas.contains(parejaKey1) && !parejasEncontradas.contains(parejaKey2)) {
                        System.out.println(pA.getNombre() + " y " + pB.getNombre() + " podrían ser pareja.");
                        parejasEncontradas.add(parejaKey1);
                    }
                }
            }
        }
        if (parejasEncontradas.isEmpty()) {
            System.out.println("No se encontraron parejas con cumplimiento mutuo de requisitos.");
        }
    }
}

Entradas relacionadas: