• No se han encontrado resultados

FUNDAMENTOS DE PROGRAMACIÓN Curso: 2012/13 OBJETIVOS

N/A
N/A
Protected

Academic year: 2022

Share "FUNDAMENTOS DE PROGRAMACIÓN Curso: 2012/13 OBJETIVOS"

Copied!
5
0
0

Texto completo

(1)

BOLETÍN 4: LIST, SET, SORTEDSET Y COLLECTIONS Versión: 1.0.0

OBJETIVOS

 Profundizar en el uso de las interfaces List y Set.

 Aprender el uso de la interfaz SortedSet, usando orden natural y órdenes alternativos.

 Aprender a usar la clase de utilidad Collections.

EJERCICIOS

1. Un museo guarda información sobre sus visitantes. En concreto tiene dos conjuntos de personas, que se denominan anterior y actual, que contienen las personas que visitaron el museo el año pasado y el año actual, respectivamente. En la clase de utilidad Museos deben escribirse los siguientes tres métodos:

public static Set<Persona> repiten(Set<Persona> anterior, Set<Persona> actual)

Devuelve las personas que han venido el año pasado y también el actual.

public static Set<Persona> todos(Set<Persona> anterior, Set<Persona> actual)

Devuelve el conjunto de las personas que han venido cualquiera de los dos años.

public static Set<Persona> nuevos(Set<Persona> anterior, Set<Persona> actual)

Devuelve el conjunto de las personas que han venido en el año actual pero no en el anterior.

De las personas que visitan el museo se conoce el DNI, el nombre y los apellidos.

Escriba una clase TestMuseos para comprobar que todo funciona correctamente.

2. El museo también guarda información sobre los idiomas que hablan sus visitantes, con el objeto de elaborar unas audioguías. En concreto se centran en los idiomas español, inglés y francés. Los visitantes del museo están almacenados en tres conjuntos, denominados espanol, ingles y frances, que contienen las personas que entienden cada uno de esos idiomas. Téngase en cuenta que puede haber personas que hablen uno, dos o los tres idiomas. En la misma clase de utilidad Museos del ejercicio anterior escriba los siguientes tres métodos:

public static Set<Persona> espanolYOtro(Set<Persona> espanol, Set<Persona> ingles, Set<Persona> frances)

Devuelve el conjunto de las personas que entienden español y otro u otros idiomas más.

public static Set<Persona> alMenosDos(Set<Persona> espanol, Set<Persona> ingles, Set<Persona> frances)

Devuelve el conjunto de las personas que entienden al menos dos idiomas.

public static Set<Persona> soloUno(Set<Persona> espanol, Set<Persona> ingles, Set<Persona> frances) Devuelve el conjunto de las personas que sólo entienden un idioma.

Añada a la clase TestMuseos el código necesario para probar que todo funciona correctamente.

(2)

3. Añada el código siguiente al método main de la clase TestLibro (al final del enunciado se da el código de los métodos mostrarLibroConPaginas, mostrarConjuntoLibros y mostrarArrayLibros para añadir a la clase Libros):

Escriba el comparador ComparadorLibrosNumPaginas1, que compara los libros solo por el número de páginas, sin desempatar por ningún otro criterio. Recordemos que

ComparadorLibroNumPaginas compara los libros por número de páginas y en caso de empate, desempata por el orden natural de los libros.

Observe qué ocurre cuando se utiliza el orden natural: desaparecen los libros “duplicados”. Pero también desaparecen libros cuando se utiliza el Comparador 1: todos los que tienen el mismo número de páginas que uno que ya esté insertado. Con el Comparador 2 vuelven a aparecer todos, pero, ¿tiene sentido que haya dos libros con el mismo título e ISBN, pero distinto número de páginas?

Libro l9 = new LibroImpl("8433912478987",

"La Guía del Autoestopista Galáctico",

new PersonaImpl("????????", "Douglas", "Adams"), 215, 19.95, true);

Libros.mostrarLibroConPaginas(l9);

Libro l10 = new LibroImpl("9788433914491", "El Inocente", new PersonaImpl("????????", "Ian", "McEwan"), 215, 12.85, false);

Libros.mostrarLibroConPaginas(l10);

Libro l11 = new LibroImpl("9788437605227", "El Árbol de la Ciencia", new PersonaImpl("????????", "Pío", "Baroja"),

304, 8.60, false);

Libros.mostrarLibroConPaginas(l11);

Libro l12 = new LibroImpl("9788437605227", "El Árbol de la Ciencia", new PersonaImpl("????????", "Pío", "Baroja"),

215, 8.60, false);

Libros.mostrarLibroConPaginas(l12);

mostrar("\nOrden natural:");

SortedSet<Libro> ss1 = new TreeSet<Libro>();

ss1.add(l9);

ss1.add(l10);

ss1.add(l11);

ss1.add(l12);

Libros.mostrarConjuntoLibros(ss1);

mostrar("\nOrden ComparadorNumPaginas1:");

SortedSet<Libro> ss2 = new TreeSet<Libro>(new ComparadorLibroNumPaginas1());

ss2.add(l9);

ss2.add(l10);

ss2.add(l11);

ss2.add(l12);

Libros.mostrarConjuntoLibros(ss2);

mostrar("\nOrden ComparadorNumPaginas:");

SortedSet<Libro> ss3 = new TreeSet<Libro>(new ComparadorLibroNumPaginas());

ss3.add(l9);

ss3.add(l10);

ss3.add(l11);

ss3.add(l12);

Libros.mostrarConjuntoLibros(ss3);

(3)

Añada a continuación el siguiente código:

Observe que ahora sí se conservan todos los libros cuando se usa el orden natural.

Observe que en el array ordenado por el criterio de ordenación 1, que solo tiene en cuenta el número de páginas, los libros con el mismo número de páginas están en orden natural: el orden alfabético de título; ¿podría dar alguna explicación razonable?

4. Vamos a ver a continuación las prestaciones de las implementaciones de las listas. Cree una clase

TestImplementacionesListas con el siguiente código:

// Código para la clase Libros

public static void mostrarLibroConPaginas(Libro l) {

String s = l.toString() + " - Págs: " + l.getNumPaginas();

mostrar(s);

}

public static void mostrarConjuntoLibros(SortedSet<Libro> s) { for (Libro l: s) {

mostrarLibroConPaginas(l);

} }

public static void mostrarArrayLibros(Libro[] al) { for (Libro l: al) {

mostrarLibroConPaginas(l);

} }

Libro[] arrayLibros = new Libro[4];

arrayLibros[0] = l9;

arrayLibros[1] = l10;

arrayLibros[2] = l11;

arrayLibros[3] = l12;

mostrar("\nArray de libros original:");

Libros.mostrarArrayLibros(arrayLibros);

Arrays.sort(arrayLibros);

mostrar("\nArray de libros ordenados por orden natural:");

Libros.mostrarArrayLibros(arrayLibros);

Arrays.sort(arrayLibros, new ComparadorLibroNumPaginas1());

mostrar("\nArray de libros ordenados por orden de páginas, " +

"ComparadorLibroNumPaginas1:");

Libros.mostrarArrayLibros(arrayLibros);

Arrays.sort(arrayLibros, new ComparadorLibroNumPaginas());

mostrar("\nArray de libros ordenados por orden de páginas, " +

"ComparadorLibroNumPaginas:");

Libros.mostrarArrayLibros(arrayLibros);

package fp.test;

import java.util.ArrayList;

import java.util.LinkedList;

import java.util.List;

import java.util.Random;

public class TestImplementacionesListas extends Test { private static final int NUM_INSERCIONES = 1000000;

private static final int NUM_INSERCIONES_PRINCIPIO = 10000;

private static final int NUM_BUSQUEDAS = 5000;

private static final int NUM_BORRADOS = 5000;

private static final int NUM_ACCESSOS = 5000;

private static final int MAX_VALUE = 100000;

(4)

private static Random rand = new Random();

private static long tiempoAntes, tiempoDespues;

public static void main(String[] args) { List<Integer> arrayList, linkedList;

arrayList = new ArrayList<Integer>();

linkedList = new LinkedList<Integer>();

mostrar("TEST DE INSERCIÓN SECUENCIAL========================");

mostrar("Vamos a insertar " + NUM_INSERCIONES + " elementos secuencialmente...");

testInsercion(arrayList);

testInsercion(linkedList);

mostrar("TEST DE INSERCIÓN AL PRINCIPIO======================");

mostrar("Vamos a insertar " + NUM_INSERCIONES_PRINCIPIO + " elementos al principio...");

testInsercionPrincipio(arrayList);

testInsercionPrincipio(linkedList);

mostrar("TEST DE BÚSQUEDA AL AZAR============================");

mostrar("Vamos a buscar " + NUM_BUSQUEDAS + " elementos al azar...");

testBusqueda(arrayList);

testBusqueda(linkedList);

mostrar("TEST DE ACCESO POR ÍNDICE==============================");

mostrar("Vamos a acceder a " + NUM_ACCESSOS + " elementos por índice...");

testAcceso(arrayList);

testAcceso(linkedList);

mostrar("TEST DE BORRADO ELEMENTOS INICIALES=================");

mostrar("Vamos a borrar " + NUM_BORRADOS + " elementos del principio...");

testBorrado(arrayList);

testBorrado(linkedList);

}

private static void testInsercionPrincipio(List<Integer> l) { tiempoAntes = System.currentTimeMillis();

for (int i = 0; i < NUM_INSERCIONES_PRINCIPIO; i++) { l.add(0, rand.nextInt(MAX_VALUE));

}

tiempoDespues = System.currentTimeMillis();

mostrar(l.getClass().getName() + ":\t" + (tiempoDespues - tiempoAntes) + " milisegundos");

}

private static void testInsercion(List<Integer> l) { tiempoAntes = System.currentTimeMillis();

for (int i = 0; i < NUM_INSERCIONES; i++) { l.add(rand.nextInt(MAX_VALUE));

}

tiempoDespues = System.currentTimeMillis();

mostrar(l.getClass().getName() + ":\t" + (tiempoDespues - tiempoAntes) + " milisegundos");

}

private static void testBusqueda(List<Integer> l) { tiempoAntes = System.currentTimeMillis();

for (int i = 0; i < NUM_BUSQUEDAS; i++) { l.contains(rand.nextInt(MAX_VALUE));

}

tiempoDespues = System.currentTimeMillis();

mostrar(l.getClass().getName() + ":\t" + (tiempoDespues - tiempoAntes) + " milisegundos");

}

(5)

Este código crea dos listas usando cada una de las dos implementaciones existentes. A continuación hace lo siguiente en las dos listas: inserta 1.000.000 de enteros aleatorios secuencialmente; inserta 10.000 elementos en la posición 0; hace 5.000 búsquedas de elementos elegidos al azar; borra 5.000 elementos de índices elegidos al azar; por último, accede a 5.000 posiciones (mediante su índice) elegidas al azar. Para cada una de esas operaciones muestra el tiempo, en milisegundos, empleado en cada una de las dos implementaciones. Interprete los resultados.

Para ello, tenga en cuenta que debajo de la implementación mediante ArrayList hay un array de longitud fija en el que se accede a los elementos mediante el índice; cuando el array se llena, se mueven todos sus elementos a un nuevo array del doble del tamaño del anterior, etc. Insertar en un punto del array que no sea el final implica que el elemento que está en la posición en la que se inserta y superiores deben ser movidos un lugar hacia delante. Lo mismo ocurre cuando se borra:

los que están por encima del que se elimina tienen que ser desplazados un lugar hacia abajo.

En la implementación mediante LinkedList, los elementos están formando una cadena en la que cada uno sabe quién es el anterior y el siguiente. Para acceder a uno en concreto (que no sea el último, que está localizado por la propia lista), debe recorrerse la cadena desde el principio avanzando por los enlaces hacia delante tantas veces como indique el índice. Para borrar un elemento simplemente se elimina el eslabón de la cadena, pero para saber cuál es el que hay que borrar hay que localizarlo, lo que exige recorrer la cadena como en los accesos.

Nota: Explicación para la pregunta formulada al final del ejercicio 3.

La segunda ordenación se realiza sobre el array resultante de la primera ordenación, que deja los libros ordenados por el orden natural. Las ordenaciones que realiza el método sort de la clase Arrays es estable: esto significa que el orden relativo de los elementos con la misma clave (elementos “empatados”) se mantiene después de la ordenación. En este caso, los elementos que tenían el mismo número de páginas, una vez ordenados por el segundo criterio, mantendrán el orden relativo que tenían antes de la segunda ordenación y después de la primera: el orden natural.

private static void testAcceso(List<Integer> l) { tiempoAntes = System.currentTimeMillis();

Integer n = 0;

for (int i = 0; i < NUM_ACCESSOS; i++) {

n = l.get(rand.nextInt(NUM_INSERCIONES));

n++; // por hacer algo con la variable }

tiempoDespues = System.currentTimeMillis();

mostrar(l.getClass().getName() + ":\t" + (tiempoDespues - tiempoAntes) + " milisegundos");

}

private static void testBorrado(List<Integer> l) { tiempoAntes = System.currentTimeMillis();

for (int i = 0; i < NUM_BORRADOS; i++) { l.remove(i);

}

tiempoDespues = System.currentTimeMillis();

mostrar(l.getClass().getName() + ":\t" + (tiempoDespues - tiempoAntes) + " milisegundos");

} }

Referencias

Documento similar