Práctica 4. Estudio Experimental de la Eficiencia de algunos

Anuncio
ESTRUCTURAS DE DATOS Y ALGORITMOS
Escuela Técnica Superior de Ingenierı́a Informática
Curso 2010-2011
Práctica 4. Estudio Experimental de la Eficiencia de
algunos métodos de Ordenación
Duración: 1 sesión
1.
Objetivo de la práctica
El objetivo de esta práctica consiste en realizar el análisis Experimental, o a-posteriori, del coste
temporal de tres algoritmos de Ordenación estudiados en teorı́a: Inserción Directa, Quick Sort y
Merge Sort; ello permitirá, además, compararlos entre sı́ y observar cómo la aplicación de la estrategia
Divide y Vencerás permite resolver recursiva y eficientemente problemas tan significativos como el de
la Ordenación.
2.
Descripción del problema
Este estudio de costes se va a realizar sobre arrays de figuras generadas aleatoriamente. El tipo de
figura (Circulo, Rectangulo o Cuadrado) se escogerá aleatoriamente, de igual forma que su tamaño
(su radio, su base y altura o su lado, dependiendo del tipo de figura). Puesto que el color de la figura
no es relevante para la ordenación, todas las figuras generadas serán de color negro.
2.1.
La clase Ordenacion
La clase Ordenacion proporciona algunos métodos estáticos para ordenar un array de elementos
de tipo genérico que implementen el interfaz Comparable<T>. Esta clase se encuentra disponible en
PoliformaT y debe incluirse dentro de un nuevo subpaquete, denominado operacionesArray, dentro del
paquete librerias.util que se creó en prácticas anteriores. Si se genera la documentación del paquete,
se podrá estudiar las caracterı́sticas de las operaciones proporcionadas en el mismo.
2.2.
Estudio experimental de la eficiencia de un algoritmo
Como ya se vio durante el curso pasado, el estudio experimental de la eficiencia de un algoritmo
conlleva la elaboración de conjuntos de prueba que reflejen condiciones diferentes de funcionamiento
del mismo (caso en que el algoritmo se comporta mejor, en que se comporta peor, aleatorio, etc.)
realizado para volúmenes de datos, o tallas, crecientes del problema.
A medida que se generan los distintos casos de prueba, o bien posteriormente, se somete el o los algoritmos a dichos casos, determinándose para cada uno de ellos una medida del esfuerzo computacional
necesario para su resolución (dicha medida suele ser el tiempo de ejecución).
Por último, los resultados se tabulan y se presentan adecuadamente. Además, en estudios del
tiempo promedio será necesario generar, para cada posible talla, diferentes instancias aleatorias, de
forma que la medida final será un promedio de las efectuadas individualmente.
1
2.3.
Medida del tiempo de ejecución (temporización)
Tal como se comentó en PRG, la temporización consiste en medir el tiempo de ejecución de un
programa o segmento de programa utilizando alguna rutina del sistema. Naturalmente, si se trabaja en
un sistema de tiempo compartido, se deberá tomar precauciones para que las medidas que se realicen
sean independientes, en lo posible, de la carga del sistema.
En el lenguaje Java existe, dentro de la clase System, el método currentTimeMillis() que devuelve el número de milisegundos transcurridos desde cierto instante inicial (1 de enero de 1970) hasta
el momento en que se efectúa la llamada. El valor que devuelve dicho método es de tipo entero largo
(long). Mediante la diferencia entre dos llamadas sucesivas al método currentTimeMillis() se puede
obtener el tiempo, en milisegundos, transcurrido entre ambas. Considérese, por ejemplo, el siguiente
fragmento de programa:
long t1 = System.currentTimeMillis();
S;
long t2 = System.currentTimeMillis();
long tiempo = t2 - t1;
//
//
//
//
medida 1 de tiempo
cualquier instrucción
medida 2 de tiempo
tiempo de ejecución de S
Cuando se temporiza un fragmento de programa, deben colocarse cuidadosamente las instrucciones
de temporización, evitando incluir entre las mismas toda aquella parte de código no correspondiente
al mismo.
3.
Actividades en el laboratorio
Para el desarrollo de esta práctica se proponen las siguientes actividades a desarrollar:
3.1.
Creación del paquete operacionesArray
El alumno deberá crear un nuevo paquete denominado librerias.util.operacionesArray. A este nuevo
paquete se deberá añadir la clase Ordenacion, disponible en PoliformaT.
La clase Ordenacion proporciona diversos métodos para la ordenación de arrays genéricos: insercionDirecta, quickSort y mergeSort. Se aconseja generar la documentación del paquete para estudiar
con mayor detalle los perfiles de las operaciones implementadas en esta clase.
3.2.
Implementación del interfaz Comparable<Figura>
Los métodos de ordenación que se van a analizar son insercionDirecta, quickSort y mergeSort.
Para estudiar su comportamiento vamos a medir el tiempo que necesitan para ordenar varios grupos
de figuras generados aleatoriamente. Para ello es necesario que la clase Figura implemente el interfaz
Comparable<Figura>. El alumno deberá modificar convenientemente la clase Figura para que dos
figuras puedan ordenarse de acuerdo a su área.
3.3.
Comparación de los métodos de ordenación
En PoliformaT se proporciona la clase TestOrdenacion, que se habrá de incluir dentro del paquete
aplicaciones.figuras.gestionFiguras. Esta clase se encarga de comparar el coste de los tres métodos de
ordenación arriba mencionados y de mostrar el resultado por pantalla de forma tabulada.
El alumno deberá completar el método comparar de la clase TestOrdenacion, que se encarga
de comparar el coste temporal de los dos métodos de ordenación que recibe como parámetros. Este
método muestra por pantalla el tiempo de ejecución en promedio de dichos métodos para arrays de
figuras generados aleatoriamente, y con tallas sucesivamente crecientes: 1000, 2000, 3000, 4000, . . .,
9000 y 10000 figuras. La clase TestOrdenacion dispone de dos métodos que son de gran utilidad para
esta tarea:
crearArrayDeFiguras: crea un array de figuras aleatorias de la talla indicada.
2
ordenarArrayDeFiguras: ordena un array de figuras, utilizando el método de ordenación indicado, y devuelve el tiempo empleado en el proceso.
Para cada una de estas tallas se ejecutará el algoritmo de ordenación un cierto número de veces, que
será distinto para cada método de ordenación y que está definido en el atributo NUM_REPETICIONES. De
esta forma se podrá obtener el coste medio como la media aritmética de las medidas tomadas. La salida
del programa deberá ser tabulada, con un formato legible, similar al que se muestra a continuación:
# Ordenacion por Ins. directa y Quicksort
# Tiempos de ejecucion promedio
# Talla
#
1000
2000
3000
4000
5000
6000
7000
8000
9000
10000
Tiempo (mseg)
Ins. directa
15,80
46,80
78,00
137,20
215,40
318,20
424,40
561,60
702,00
873,80
Tiempo (mseg)
Quicksort
3,29
3,10
1,90
2,21
2,94
3,46
4,37
5,32
5,78
7,02
Una vez completado el código, se deberá ejecutar el método main de la clase TestOrdenacion
y probar las tres opciones del menú para verificar que los métodos de ordenación implementados
funcionan correctamente y estudiar cuál de los tres métodos es el más eficiente.
3.4.
Interpretación de los resultados
Habitualmente, la interpretación de los resultados obtenidos mediante un proceso de temporización
similar al realizado se facilita representando los resultados de forma gráfica. Para ello, se sitúan en
abscisas valores crecientes de la talla, mientras que en ordenadas se representan los tiempos de ejecución. Además, para poder prever tiempos de ejecución fuera del rango de tallas medido, es conveniente
ajustar los resultados mediante una función matemática de forma que, sustituyendo en la misma los
valores de talla deseados, sea posible deducir el comportamiento temporal requerido.
Hoy en dı́a, mediante el uso de hojas de cálculo (OpenOffice, por ejemplo), o de programas más
especializados de interpretación y presentación gráfica (gnuplot, por ejemplo) es posible realizar la
representación gráfica de los resultados. Por ejemplo, para obtener la gráfica correspondiente al método
de insercionDirecta en el gnuplot se deben seguir los siguientes pasos:
1. Se guardan los resultados de la comparativa (opción 2 del menú) en un fichero llamado, por
ejemplo, tiempos.dat. Para ello se aconseja:
Activar la opción ”Clear screen at method call”del terminal antes de ejecutar el programa.
Guardar el fichero mediante la opción ”Save to file...”del terminal una vez obtenidos los
resultados. El fichero obtenido deberá editarse para eliminar las lı́neas correspondientes al
menú de la aplicación.
2. Lanzar el gnuplot. Para visualizar los datos obtenidos basta con escribir:
plot ’tiempos.dat’ using 1:2
El parámetro 1:2 indica que las columnas que se utilizarán para obtener la gráfica serán 1 (donde
se muestra la talla del problema) y la 2 (donde están los tiempos de insercionDirecta).
3
3. Ajustar los resultados a un polinomio de segundo grado para poder predecir el comportamiento
del método para tallas más grandes. Para ello se crea una nueva función con tres parámetros (a,
b y c) para, posteriormente, ajustar el valor de dichos parámetros:
insDir(x) = a*x**2 + b*x + c
fit insDir(x) ’tiempos.dat’ using 1:2 via a,b,c
4. Tras el ajuste la función obtenida es:
insDir(x) = 8,977e − 06 ∗ x2 − 0,00364 ∗ x + 11,3
Finalmente, mostramos la gráfica resultante (ver Figura 1), con los tiempos obtenidos y con la
función de ajuste:
plot ’tiempos.dat’ using 1:2, insDir(x)
Figura 1: Inserción directa, tiempo promedio. Ajuste a una parabola.
Del mismo modo, podemos ajustar los resultados obtenidos con el método quickSort a una curva
de tipo x*log(x). Tras el ajuste se obtiene:
quick(x) = 0,00116 ∗ x ∗ log(x) − 0,0106 ∗ x + 5,724
Figura 2: Quicksort, tiempo promedio. Ajuste a curva x*log(x).
Naturalmente, ahora es sencillo predecir el comportamiento temporal de cualquiera de los dos algoritmos mediante el uso de las funciones de ajuste. Estúdiese, por ejemplo, cuánto tiempo emplearı́an
ambos algoritmos en ordenar una array de un millón de elementos.
4
Descargar