PR´ACTICA 1 – Colas de prioridad

Anuncio
ESTRUCTURA DE DATOS Y DE LA INFORMACIÓN 2
PRÁCTICA 1 – Colas de prioridad
Calendario de entregas
grupo
1a
1b
2a
2b
2c
2d
3b
3c
comienzo
miércoles 17/2
jueves 18/2
viernes 19/2
lunes 15/2
martes 16/2
jueves 18/2
jueves 18/2
martes 16/2
entrega
miércoles 3/3
jueves 4/3
viernes 5/3
lunes 1/3
martes 2/3
jueves 4/3
jueves 4/3
martes 2/3
ENUNCIADO DE LA PRÁCTICA
En esta práctica se creará una librerı́a para la gestion de colas de prioridad basado en heaps, y varios programas
que la utilizan. La librerı́a deberá ser completamente abstracta, es decir, las funciones de librerı́a no ”saben” que
datos están contenidos en el heap. Para la librerı́a, la cadena que constituye el heap es una cadena de punteros a
void (void **).
Para su funcionamiento,el heap necesita comparar elementos, y esta comparación depende de lo que hay en los
elementos. Si la librerı́a es abstracta, esta comparación no se puede hacer dentro de la librerı́a ya que, si no,
tendrı́amos que cambiar la librerı́a cada vez que se cambian los datos. El problema se soluciona pasando a la
librerı́a como parametro, la función de comparación que hay que utilizar. Por esto, en el fichero heap.h se define
el tipo de la función de comparación
typedef int (*comp_f)
(void *i, void *j);
La declaración comp_f f; indica que f es el puntero a una función de este tipo. La función recibe como parámetros
dos punteros a void, que apuntarán a dos elementos del heap, y devuelve el resultado:
-1: el elemento i precede al elemento j;
0: los dos elementos son iguales;
1: el elemento j precede el elemento i;
Cabe notar que hemos dicho precede, y no es mayor que. Esta interfaz es similar a la de otras funciones de
comparación en C como las que usan qsort o bsearch. Podéis usar tambin cualquier valor negativo en lugar de
-1, y cualquier valor positivo en lugar de 1. En esta práctica se utilizarán heaps con datos relativo a personas,
y cada elemento del heap contendrá el apellido y el DNI de una persona. Hay cuatro maneras de ordenar estos
datos:
1
i) por DNI en orden ascendiente;
ii) por DNI en orden descendiente;
iii) por apellido en orden alfabético;
iv) por apellido en orden alfabético inverso.
Para cada una de estas posibilidades habrá que crear una función de comparación de tipo comp_f. Por ejemplo,
la función de comparación para el caso i) devolverá -1 si el elemento i tiene un DNI menor que el elemento j,
mientras que la función de comparación para el caso ii) devolverá -1 si el elemento i tiene un DNI mayor que
el elemento j. Las funciones de comparación para los casos iii) y iv) se comportarán de la misma manera, pero
haciendo la comparación de los apellidos.
La función de comparación se pasa como parametro a la función de creación del heap y se almacena en un campo
de la estructura de heap.
Un aspecto importante de la práctica es que la cola de prioridad debe permitir su actualización cuando se “decrementa” la “prioridad” asociada a un dato, es decir, se cambia su clave asociada con el posible resultado de que
ese dato suba hacia arriba en el heap. Para poder hacer esto con la complejidad teórica vista en clase para las
colas de prioridad, es necesario mantener un ı́ndice en el heap que indica, para cada elemento, cuál es su posición
en ppdatos. Para ello, es necesario actualizar esta posición cada vez que se cambia en cualquiera de las funciones
de heap. Para ello, los datos que se pasan para crear el heap son almacenados en un struct que contiene el dato
como tal (como puntero a void) y un ı́ndice que creamos nosotros, y que servirá como ı́ndice en el array posicion
que almacenamos dentro de la estructura del heap.
*
*
*
Ejercicio 1
Escribir las funciones de manejo de heaps y colas de prioridad definidas en el fichero heaps.h. Es obligatorio
seguir el prototipado de las funciones definidas en este fichero cabecera.
Ejercicio 2
Para probar las funciones escritas anteriormente, escribir un programa que genere un heap a partir de los datos
de DNI y nombres contenidos en el fichero de texto dni.txt. Este fichero tiene como primera lı́nea un entero
representando el nmero total de datos, y a continuacin la lista de datos (un dato por lı́nea). El programa (de
nombre heaps_1) aceptará, por este orden, los siguientes parámetros en la lı́nea de comandos:
i) Nombre del fichero a procesar
ii) Flag indicando el criterio de ordenación en el heap (1=ascendente; 0=descendiente)
iii) Flag indicando el campo sobre el que opera la ordenación (0=DNI; 1=nombre)
iv) Flag indicando el tipo de operación (0=generar heap (hpBuildHeap); 1=ordenar datos (hpHeapsort))
v) Nombre del fichero de salida (formato igual que el fichero de entrada). Las datos se escriben segn el orden en
que aparecen en el array que contiene el heap.
2
Ejemplo:
heaps_1
dni.txt
1
1
1
salida.txt
genera un heap ascendente sobre el nombre con los datos contenidos en el fichero ”dni.txt”, ordena las claves
con hpHeapsort, y guarda los datos resultantes en el fichero ”salida.txt” (Heapsort sobre un heap ascendente
proporciona las claves ordenadas de mayor a menor). El fichero de salida debe tener el mismo formato que el
”dni.txt”, y en particular debe poder ser procesado por el programa heaps_2 del siguiente ejercicio.
Ejercicio 3
Escribir un programa que, dado un fichero de texto en el formato habitual (ej. dni.txt), indique si el fichero
representa un heap. En particular, el programa deberá escribir en pantalla:
i) si el fichero representa un heap ascendente, un heap descendiente, o está desordenado respeto al DNI;
ii) si el fichero representa un heap ascendente, un heap descendiente, o está desordenado respeto al nombre;
El fichero pasado como argumento se interpreta de la siguiente manera: el nodo compuesto por el par ”DNI
NOMBRE” de la lı́nea i-ésima es el padre de los nodos que se encuentran en las lı́neas (2*i)-ésima y (2*i+1)-śima.
El programa (de nombre heaps_2 ) acepta como parámetro el nombre del fichero y devuelve la respuesta por la
salida estándar.
Ejemplo: heaps_2 dni.txt
Ejercicio 4
Escribir un programa para probar la rutina de inserción de datos en un heap, hpHeapInsert. El programa (de
nombre heaps_3) generará un heap a partir de los datos contenidos en un fichero (usar dni.txt). Tras esto, el
programa abrirá un segundo fichero de datos (usar dni_nuevos.txt) e insertará de uno en uno los datos de este
fichero en el heap creado, mediante llamadas oportunas a hpHeapInsert. Una vez insertados todos los datos, el
programa escribirá en un fichero de salida los datos del heap resultante. El programa aceptará, por este orden, los
siguientes parámetros en la lı́nea de comandos:
i) Nombre del fichero con los datos iniciales
ii) Nombre del fichero con los datos a insertar
iii) Flag indicando el criterio de ordenación en el heap (1=ascendente; 0=descendiente);
iv) Flag indicando el campo sobre el que opera la ordenaciń (0=DNI; 1=nombre);
v) Nombre del fichero de salida
Ejemplo:
heaps_3
dni.txt
dni_nuevos.txt 0
0
salida.txt
Nota: Recordad que debı́s emplear un ńico fichero Makefile para generar los ejecutables.
3
Descargar