Estructura de Datos: Tarea 1 Complejidad de Algoritmos

Anuncio
Estructura de Datos: Tarea 1
Complejidad de Algoritmos
Profesor: Mauricio Solar.
Ayudante de Tareas: José Luis Canepa.
Última compilación: 25 de agosto de 2009
Índice
1. Introducción
1.1. Explicación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2. Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
2
2
2. Descripción de la Tarea
2.1. Algoritmos a analizar . . . . . . . . . . . . .
2.1.1. Búsqueda Secuencial . . . . . . . . . .
2.1.2. Búsqueda Binaria . . . . . . . . . . .
2.1.3. Búsqueda Secuencial Paralela . . . . .
2.2. Implementación de cada algoritmo y pruebas
2.3. Graficación . . . . . . . . . . . . . . . . . . .
2.4. Preguntas al respecto . . . . . . . . . . . . . .
2
2
2
3
3
3
4
4
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3. Evaluación
4
4. Entrega
4.1. Entrega del código . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2. Entrega del informe . . . . . . . . . . . . . . . . . . . . . . . . .
4.3. Contacto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
5
5
5
5. Apéndice
5.1. Compilar en Linux con gcc . . . . . . . . .
5.2. Usar la librerı́a entregada . . . . . . . . . .
5.3. ¿Por qué un archivo binario en potencias de
5.4. En caso de problemas con el archivo binario
5
5
6
7
8
1
. . .
. . .
diez?
. . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1.
1.1.
Introducción
Explicación
Como se ha visto en clases, distintos algoritmos proveen diferentes grados de
uso de memoria (complejidad Espacial) y el tiempo de ejecución (expresado en
la cantidad de veces que se deben recuperar/leer los datos) en base a la entrada
(de tamaño “n”).
La tarea consiste en 3 fases, una en la que se probarán tres algoritmos conocidos, luego una etapa de graficación, y finalmente responder un cuestionario al
respecto de la experiencia.
Para realizar la tarea utilizará el lenguaje C en Linux (disponible en los
laboratorios de informática o en bajar una copia de Ubuntu) y compilado con
“gcc” (ver sección 5.1). Conste que si intenta desarrollar la tarea en windows,
es probable que al momento de probar la tarea en linux se produzcan errores
dado que gcc de linux es mas estricto.
1.2.
Objetivos
1. Entender el cálculo de complejidad de algoritmos.
2. Conocer tres formas de realizar búsquedas, que serán útiles para ARI.
3. Tener una referencia de como cargar archivos binarios y uso de malloc.
4. Aprender a compilar en Linux con gcc y trabajar con librerı́as.
2.
2.1.
Descripción de la Tarea
Algoritmos a analizar
Los algoritmos a continuación representan métodos de búsqueda entre dos
arreglos. Se lee un arreglo (ordenado o desordenado) y cada entrada es buscada
en el segundo arreglo (ordenado o desordenado).
El arreglo del que se leerán los números a buscar se llama arreglo M (tiene
m enteros en su interior), y en el que se buscarán, se llama N (y tiene n en su
interior). Conste que se considera “encontrado” en el instante en que encuentran
el dato, no es necesario que encuentren las repeticiones.
2.1.1.
Búsqueda Secuencial
Arreglo M ordenado, N desordenado.
Consiste en recorrer, por cada elemento del arreglo M, el contenido del arreglo N hasta encontrar el término o llegar hasta el final.
2
2.1.2.
Búsqueda Binaria
Arrelgo M desordenado, N ordenado.
Se recorre el arreglo M, y por cada elemento de este se hace una búsqueda
binaria en el arreglo N. La búsqueda binaria solo se puede realizar en arreglos
ordenados, y se parte por la mitad del arreglo, luego se determina si el valor
buscado está en la sección previa o posterior a la división, y se repite. Investiguen
más sobre este algoritmo, es bastante conocido.
2.1.3.
Búsqueda Secuencial Paralela
Arreglo M ordenado, N ordenado.
Este algoritmo no tiene un nombre “oficial” dado que es bastante básico.
Consiste en recorrer el arreglo M y el N al mismo tiempo, por cada elemento en
M se busca hasta encontrar el término en N, pero si se encuentra uno mayor,
significa que no está, y debe procederse al siguiente de M y repetir esta idea.
2.2.
Implementación de cada algoritmo y pruebas
Cada algoritmo mencionado anteriormente debe estar programado en C, con
un nombre fácil de identificar dentro del código. Además, deben tener las cuatro
entradas especificadas a continuación:
void search_sequential(int *arrm, int *arrn, int length, bool verbose);
void search_binary(int *arrm, int *arrn, int length, bool verbose);
void search_parallel(int *arrm, int *arrn, int length, bool verbose);
(Conste que pueden ser modificadas y agregadas mas argumentos y retornos,
pero debe tener esos 4 argumentos siempre con sus mismos nombres).
Se deberá ejecutar cada algoritmo 3 veces con distintos tamaños de entrada(101 , 102 , 103 ),
ambas del mismo largo length. Para obtener el tiempo de ejecución usarán la
librerı́a estándar time.h.
El argumento verbose representa un booleano (true o false) descrito en
la librerı́a stdbool.h y significa que el programa debe imprimir a pantalla el
resultado de la búsqueda (el ı́ndice de donde está ubicado el entero) cuando
sea true, y ocultarlo en false. Esto se debe a que el imprimir a stdout consume
recursos (afectando el tiempo) y para facilitar el proceso de corrección.
Para facilitarles la tarea de cargar este archivo (utilizando almacenamiento
dinámico), serán provistos de dos archivos (.h, .c ) donde vendrá un código
pre-hecho que cargará el archivo a memoria y retornará un puntero. No están
obligados a usarlo. Mas información en la sección 5.2 (página 5.2)
(Pueden usar este código como referencia para entender como funciona la
función malloc() de C para futuros trabajos)
Finalmente, el output del programa será un archivo donde el tiempo promedio de cada ejecución vendrá separado por una coma.
3
2.3.
Graficación
Usando el archivo separado por comas, debe ser llevado a Excel para generar
un gráfico donde se comparen los tres algoritmos. El eje horizontal contendrá el
tamaño de la entrada (“n”) y el vertical el tiempo que demoró.
Nótese que este gráfico deberá venir incluido en un informe que será evaluado
bajo el modelo de informes escritos.1
2.4.
Preguntas al respecto
Responda las siguientes preguntas:
1. ¿Cuáles son las complejidades de cada uno de los algoritmos para las
entradas de tamaño m y n?
2. Suponga que tiene dos arreglos de largo m y n desordenados. El arreglo
M tiene 10 elementos y el N tiene 1000. Utilizando un algoritmo como
Quicksort, convendrı́a ordenar uno o los dos archivos antes de realizar la
búsqueda? ¿Qué ocurre en el caso opuesto (m=1000, n=10)? Suponga que
Quicksort es siempre O(xlogx) (donde X es el arreglo a ordenar de largo
x).
3.
Evaluación
Los puntos por cada categorı́a son:
1. Implementación (55 puntos)
a)
b)
c)
d)
Presentación (5 puntos)
Búsqueda Secuencial (10 puntos)
Búsqueda Binaria (20 puntos)
Búsqueda Sec. Paralela (20 puntos)
2. Graficación (15 puntos)
3. Preguntas (30 puntos)
a) Complejidades (15 puntos)
b) Caso ejemplo (15 puntos)
Errores en la compilación (-Wall) descuentan 5 puntos cada uno hasta un
total de 15 puntos. Errores en tiempo de ejecución (e.g. Segmentation Fault)
serán causante de obtener un 0 en la primera parte. La presentación del código
debe ser clara (buenos nombres de variable, código comentado, bien indentado).
En cuanto a la implementación del algoritmo, será evaluado con buena nota
si efectivamente encuentra y es el algoritmo descrito. En caso de errores al buscar
se descontarán puntos.
El gráfico deberá estar bien formateado (rótulo de tı́tulo, ejes) y ser representativo, conforme a las reglas del formato de informe de investigación1 .
4
4.
4.1.
Entrega
Entrega del código
Deben mandar el código comprimido en un archivo “.tar.gz” con el nombre
de su grupo (Ejemplo: “grupo06.tar.gz”) (Para comprimir, botón derecho en
ubuntu y tienen .tar.gz ahı́).
Un archivo explicando como se usa su tarea y supuestos utilizados: “readme.txt”.
Nombres y roles de los integrantes deberán venir en dicho “readme.txt”.
Código fuente pedido de la sección 2.2.
4.2.
Entrega del informe
Gráficos, respuesta a las preguntas deben ser entregados en formato de
informe de investigación1 , haciendo uso de gráficos (sección 2.3), haciendo
referencia al código C que han escrito (2.2), y demostrando empı́ricamente (con
ecuaciones) los resultados obtenidos para las preguntas de complejidad de algoritmos. El formato del archivo puede ser .odt (openoffice) o .doc (word 2003).
Los nombres y roles de los integrantes del grupo (y número del grupo) en
el mismo documento de word/openoffice, además indicando qué fue lo que
hizo cada uno de los miembros durante la tarea, tal como se les pide en
el formato 1 .
4.3.
Contacto
La tarea debe ser mandada a “[email protected]” bajo el tı́tulo
de “Inf. Exp. Lab. X Grupo Y”, con el comprimido y el informe en dos adjuntos
separados. La fecha de entrega es de dos semanas tras la publicación oficial de
la tarea (Miércoles 8 de Septiembre), hasta las 23:59.
Cualquier duda o error que encuentren sobre las reglas, escriban al mismo
mail, o preguntar en persona.
Finalmente, el código extra, el archivo de prueba y el formato lo pueden bajar
de “http://www.alumnos.usm.cl/∼jose.canepa/” en la sección de “Archivos”.
5.
5.1.
Apéndice
Compilar en Linux con gcc
Para compilar en ubuntu, de partida necesitan la librerı́a build-essential (los
laboratorios de la U ya lo tienen instalado):
sudo apt-get install build-essential
1 Formato:
Descrito
por
el
profesor,
“http://www.alumnos.usm.cl/∼jose.canepa/”.
5
será
subido
a
la
página
Ahora que la tienen, para compilar su tarea (sola) lo mas simple es:
gcc miarchivo.c -o salida
Pero, si están usando la librerı́a entregada (binarr.h), tendrán que hacer un
poco mas de trabajo, el siguiente comando compila y “linkea” ambas (Además
de -Wall para mostrar todos las alertas (Wall: “Warn all”)):
gcc -Wall binarr.c miarchivo.c -o salida
Y ahora “salida” es su ejecutable, para ejecutarlo simplemente usen:
./salida
Y si les dice que no tienen permiso de ejecutarlo, hagan:
chmod u+x salida
Esto les dará permiso de ejecución (+x) a ustedes (u = owner). Esto basta
hacerlo una sola vez.
5.2.
Usar la librerı́a entregada
La librerı́a entregada provee una interfaz para cargar un archivo binario que
ya guarda los números a probar. La razón de que se entregue esta librerı́a es
que no interesa como carguen los datos, sino el desarrollo de algoritmos.
El archivo binario que se les entregó tiene lo siguiente en su interior:
Estructura:
[int:largo] [[int][int][int][int][int][int][int]...:array de enteros]
Contenido:
10 <10 numeros aleatorios>
100 <100 numeros aleatorios>
1000 <1.000 numeros aleatorios>
10^1
10^2
10^3
De tal manera que lo que hace la librerı́a es leer el primer bloque de 4 bytes
y puede determinar cuantos enteros hay a continuación, lo que permite saltar
usando fseek() para poder encontrar el bloque exacto que se pide dependiendo
de la potencia pedida.
Para utilizarla, la librerı́a viene con simples funciones, la primera que han
de ejecutar, teniendo todos los archivos en la misma carpeta, y una vez incluida
la cabecera binarr.h, es, por ejemplo:
int* arr = binarr_load("desordenado.bin", 2);
Esto retornará un arreglo desordenado con 100 (102 ) enteros entre 0 y 100
guardado en arr. Si desean ver el contenido, pasen el puntero a la función:
6
binarr_print(arr, 2);
Y ası́ podrán ver lo que contiene (el 2 viene siendo la misma potencia anterior).
Cuando desarrollen sus funciones, tendrán que pasar como argumento el
largo, obviamente, no os sirve la potencia, hay que convertirla, para eso también
está la función math power():
int length = math_power(10, 2);
Ahora length será 100 (102 ), con lo que podrán trabajar con sus funciones.
Finalmente, cuando terminen de usar dicho arreglo, deben deshacerse de él,
dado que en C hay que especificar cuando eliminar memoria, también hay una
función:
binarr_free(arr);
Si necesitan entrar en mas detalle, lean los comentarios que vienen en el
código fuente de binarr.c.
5.3.
¿Por qué un archivo binario en potencias de diez?
Resulta mas fácil guardarlos ası́ y recuperarlos. La principal razón, es para
que al probar múltiples veces una misma función con diferentes potencias,
puedan hacer:
int i, *arr;
// Prueba de
for(i=1;
{
arrm
arrn
secuencial
i<5; i++)
= binarr_load("ordenado1.bin", i);
= binarr_load("desordenado.bin", i);
// Medir tiempo
search_sequential(arrm, arrn, math_power(10, i), false);
// Terminar de medir tiempo
/* Mas codigo */
binarr_free(arrm);
binarr_free(arrn);
}
// Prueba de binario
// ...
De tal manera que pueden colgar el proceso de carga de arreglos a un solo
entero que representa el tamaño de entrada.
7
5.4.
En caso de problemas con el archivo binario
El archivo binario tiene números que van desde 0 hasta 1.000. Si observan
que los dı́gitos están completamente fuera de esta escala (1.000+) es probable
que estén teniendo problemas para leer el archivo binario, dada la arquitectura
de su procesador.
Algunos procesadores guardan al revés los datos en memoria. Si se da el caso
que ustedes tengan datos erróneos solo por esto, escriban un correo al respecto
y subiré archivos generados al revés.
8
Descargar