Metodología y Tecnología de la Programación II Escuela Politécnica Superior, UAM, 2009 2010 Conjunto de Prácticas no. 3 Fecha de entrega: Grupo del Lunes: 11 de Enero. Grupos del Martes: 15 de Diciembre. Grupos del Miércoles: 9 de Diciembre. Grupos del Jueves: 17 de Diciembre. Grupos del Viernes: 18 de Diciembre. En estas prácticas se trata el desarrollo de la programación de árboles binarios de búsqueda. Se determinará experimentalmente el tiempo medio de ordenación de los elementos de una tabla usando para ello la construcción de un árbol binario. Además, se medirá el tiempo medio de búsqueda de elementos en un árbol construido con anterioridad. 1. Definid en el fichero arbol.h la estructura necesaria para construir los nodos de un árbol binario. typedef struct _nodoabb int info; struct _nodoabb *izq; struct _nodoabb *der; nodoabb, *pnodoabb; Implementad las siguientes rutinas en el fichero arbol.c: short Inserta Nodo(pnodoabb *pabb,int num); pnodoab Crea ABB (int *tabla, int tamanio); short Libera ABB(pnodoabb *pabb); short Imprime ABB (pnodoabb pabb); Todas las funciones devolverán OK o ERR, en función de que su desarrollo fuera el deseado o no, exceptuando Crea AB que devolverá NULL si ha ocurrido un error o bien el árbol construido, si todo se ha realizado correctamente. La función Inserta Nodo introduce el elemento num en la posición correcta del árbol definido por pabb. Crea ABB creará el árbol binário de busqueda completo utilizando para ello la función anteriormente desarrollada Inserta Nodo. Crea ABB recibirá una permutación desordenada tabla con todos los elementos a insertar en el árbol. Libera ABB liberará toda la memoria reservada por las rutinas Inserta Nodo y Crea ABB. Imprime ABB imprime el valor del campo info de cada nodo cuando el árbol se recorre en orden medio. El programa C de prueba para estas rutinas, tendrá el siguiente formato: /* Programa: P3_1_??? Fecha: */ /* Programa para comprobar un Arbol Binario */ /* de Busqueda */ 1
#include <stdlib.h> int tamanio; int *perm=null; pnodoabb pabb=null; short ret1, ret2; printf( Practica numero 3, apartado 1\n ); printf( Introduce el numero de elementos de la tabla\n ); scanf( %d,&tamanio); if(!(perm=genera_perm(tamanio))) printf( Error: No hay memoria \n ); if(!(pabb=crea_abb(perm, tamanio))) printf( Error en Crea_ABB \n ); free(perm); if(perm) free(perm); ret1=imprime_abb(pabb); ret2=libera_abb(&pabb); if(ret1==err) printf( Error en Imprime_ABB \n ); if(ret2==err) printf( Error en Libera_ABB \n ); /* Funcion: Inserta_Nodo Fecha: */ /* Vuestro comentario */ short Inserta_Nodo(pnodoabb *pabb,int num) /* Funcion: Crea_ABB Fecha: */ /* Vuestro comentario */ pnodoab Crea_ABB(int *tabla,int tamanio) /* Funcion: Libera_ABB Fecha: */ /* Vuestro comentario */ short Libera_ABB(pnodoabb *pabb) /* Funcion: Imprime_ABB Fecha: */ short Imprime_ABB(pnodoabb pabb) 2
2. Implementad la rutina short Ordena ABB (pnodoabb pabb, int* tabla ); que ordena la tabla tabla utilizando para ello un árbol binario ya creado, la salida de la rutina será OK o ERR en función de que todo se realice correctamente o bien no sea así. El programa C de prueba para verificar que la rutina ordena correctamente tendrá el siguiente formato: /* Programa: P3_2_??? Fecha: */ /* Programa para comprobar la ordenacion con */ /* Arboles Binarios */ #include <stdlib.h> int tamanio,k; int *perm=null; pnodoabb pabb=null; short ret1; printf( Practica numero 3, apartado 2\n ); printf( Introduce el numero de elementos de la tabla\n ); scanf( %d,&tamanio); if(!(perm=genera_perm(tamanio))) printf( Error: No hay memoria \n ); if(!(pab=crea_abb(perm, tamanio))) printf( Error en Crea_ABB \n ); if(perm) free(perm); perm=null; if(ordena_abb(pabb,perm)==err) printf( Error en Ordena_ABB \n ); if(perm) free(perm); perm=null; ret1=libera_abb(&pabb); for(k=0;k<tamanio;k++) /* imprimimos cada elemento */ printf( %d \t,perm[k]); printf( \n ); if(perm) free(perm); perm=null; ret1=libera_abb(&pabb); if(ret1==err) printf( Error en Libera_ABB \n ); /* Funcion: Ordena_ABB Fecha: */ short Ordena_ABB(pnodoabb pabb, int* tabla) 3
3. Definid en arbol.h los siguientes punteros a funciones: typedef short (* pfunc ABB int)(pnodoabb,int) ; typedef short (* pfunc ABB pint)(pnodoabb, int*) ; Estas definiciones serán las que nos sirvan para estudiar características distintas de los árboles binarios con tan sólo realizar pequeñas modificaciones en el código. Implementad las siguientes rutinas: double Driver ABB pint(int tamanio,int n perms, int n veces, pfunc ABB pint utilidad ); short Time ABB pint( char* fichero, int num min, int num max, int n perms int incr, int n veces, pfunc ABB pint utilidad ); La rutina Driver ABB pint devuelve el tiempo que tarda en realizar la operación requerida por utilidad con n perms permutaciones de tamaño tamanio que generarán árboles binarios; n veces es el argumento correspondiente al retardo. La rutina Time ABB pint es la que organiza la escritura en el fichero fichero de la evolución temporal promedio de la la operación requerida por utilidad con tablas de diferentes tamaños. Con todas estas funciones vamos a medir el tiempo de ordenación de tablas usando como herramienta árboles binarios. El programa C de prueba será el siguiente: /* Programa: P3_3_??? Fecha: */ /* Programa que escribe en un fichero */ /* los tiempos medios de ordenacion de */ /* una tabla mediante arboles binarios */ /* de Busqueda. */ #include <stdlib.h> int num_min,num_max,incr,n_perms,n_veces; char nombre[256]; short ret; pfunc_abb_pint caracteristica; printf( Practica numero 3, apartado 3\n ); printf( introduce el numero minimo de elementos de la tabla\n ); scanf( %d,&num_min); printf( introduce el numero maximo de elementos de la tabla\n ); scanf( %d,&num_max); printf( introduce el incremento\n ); scanf( %d,&incr); printf( Introduce el numero de permutaciones a promediar \n ); scanf( %d,&n_perms); printf( Introduce el coeficiente del retardo \n ); scanf( %d,&n_veces); printf( Introduce el nombre del fichero para guardar los tiempos\n ); scanf( %s,nombre); /* calculamos los tiempos de...*/ caracteristica = Ordena_ABB; ret=time_abb_pint( nombre, num_min, num_max, incr, n_perms, n_veces, caracteristica); 4
if(ret==err_time) /* ERR_TIME debera ser un numero negativo */ printf("error en la funcion Time_ABB_pint\n"); /* Funcion: Driver_ABB_pint Fecha: */ double Driver_ABB_pint ( int tamanio,int n_perms, int n_veces, pfunc_abb_pint utilidad ) /* Funcion: Time_ABB_pint Fecha: */ short Time_ABB_pint( char* fichero, int num_min, int num_max, int incr, int n_perms, int n_veces, pfunc_abb_pint utilidad) 4. Implementad las siguiente rutinas: short Busca Nodo(pnodoabb pabb, int num); donde Busca Nodo busca el valor num en el árbol pabb y devuelve OK si lo encuentra o ERR si no lo ha encontrado. double Driver ABB int(int tamanio,int n perms, int n veces, pfunc ABB int utilidad ); short Time ABB int( char* fichero, int num min, int num max, int incr, int n perms, int n veces, pfunc ABB int utilidad ); Las funciones double Driver ABB int y short Time ABB int son idénticas a las realizas en el apartado anterior con la salvedad de utilizar el puntero a función del tipo pfunc ABB int. Con todas estas funciones vamos a medir el tiempo medio de búsqueda de todos los elementos que componen un árbol binario de busqueda. El programa en C para la búsqueda sería: /* Programa: P3_4_??? Fecha: */ /* Programa que escribe en un fichero */ /* los tiempos medios de b\ usqueda en un */ /* arbol binario de busqueda. */ #include <stdlib.h> int num_min,num_max,incr,n_veces, n_perms; char nombre[256]; short ret; pfunc_abb_int caracteristica; printf( Practica numero 3, apartado 4\n ); printf( introduce el numero minimo de elementos de la tabla\n ); 5
scanf( %d,&num_min); printf( introduce el numero maximo de elementos de la tabla\n ); scanf( %d,&num_max); printf( introduce el incremento\n ); scanf( %d,&incr); printf( Introduce el numero de permutaciones a promediar \n ); scanf( %d,&n_perms); printf( Introduce el coeficiente del retardo \n ); scanf( %d,&n_veces); printf( Introduce el nombre del fichero para guardar los tiempos\n ); scanf( %s,nombre); /* calculamos los tiempos promedios de... */ caracteristica = Busca_Nodo; ret=time_abb_int ( nombre,num_min,num_max, incr, n_perms, n_veces, caracteristica); if(ret==err_time) /* ERR_TIME debera ser un numero negativo */ printf("error en la funcion Time_ABB_int\n"); /* Funcion: Time_ABB_int Fecha: */ short Time_ABB_int( char* fichero, int num_min, int num_max, int incr, n_perms, int n_veces, pfunc_abb_int utilidad) /* Funcion: Driver_ABB_int Fecha: */ double Driver_ABB_int ( int tamanio,int n_perms, int n_veces, pfunc_abb_int utilidad ) /* Funcion: BuscaNodo Fecha: */ short Busca_Nodo(pnodoabb pabb, int num) Cuestiones teóricas 1. En la práctica se ha pedido, en Imprime ABB, una impresión del árbol mediante un recorrido del mismo en orden medio o inorden. Indica y da un ejemplo (mínimo con un árbol de 7 elementos) de los recorridos en preorden y en postorden de un árbol binario. 2. Justifica cual sería la entrada (permutación) que produciría el caso peor y mejor en la ordenación utilizando árboles binarios Son estas entradas las mismas para la búsqueda en dichos árboles? 3. Indica el principal problema para el rendimiento de los árboles binarios para su utilización en ordenación y búsqueda. Propón una solución a este problema. 4. Utilizando los libros recomendados en la asignatura, obtén información sobre los árboles AVL. Consideras que dichos árboles solucionan el problema de los árboles binarios para la búsqueda de elementos en el árbol? Justifica 6
tu respuesta mediante un estudio teórico del crecimiento de la profundidad de un árbol binario y de un AVL, en los casos peor, mejor y medio de los árboles binarios. Material a entregar en cada uno de los apartados Documentación: La documentación constará de los siguientes apartados: 1. Introducción: Consiste en una descripción de tipo técnico del trabajo que se va a realizar, qué objetivos se pretenden alcanzar, qué datos de entrada requiere vuestro programa y que datos se obtienen de salida, así como cualquier tipo de comentario sobre la práctica. 2. Código impreso: El código de la rutina según el apartado. Como código también va incluida la cabecera de la rutina. 3. Resultados: Descripción de los resultados obtenidos, gráficas comparativas de los resultados obtenidos con los teóricos y comentarios sobre los mismos. 4. En este apartado, comparad los tiempos de búsqueda en el árbol con los de órdenación de una tabla utilizando para ello la construcción de un árbol binario. Indicad si existe alguna similitud entre los resultados de los dos últimos apartados. 5. Cuestiones: En el último apartado, incluir las respuestas en papel a las cuestiones teóricas anteriores. Esta documentación se entregará al profesor de prácticas, en el corespondiente día de entrega de práctica. En portada deberá incluirse los nombres de los alumnos con su cuenta asociada, por ejemplo, e254851. Si alguno de los alumnos no pertenece al grupo de prácticas en elque está por no corresponderse con el grupo de teoría, igualmente lo debería indicar en la portada de la práctica. Código Fuente: El código fuente será entregado en el compoartimiento de entregas de prácticas de la página Web desarrollada para tal efecto y respetando el grupo de prácticas al que pertenece el alumno. Los fuentes deberán agruparse en un fichero tar compresión gzip, y con el nombre p3gxx YY.tgz donde XX es el grupo de prácticas e YY el número de pareja. 7