Examen de Programación 2 Agosto de 2003 Generalidades: La prueba es individual y sin material. Duración: 3 hs. Sólo se contestan dudas acerca de la letra de los ejercicios. Escriba las hojas de un sólo lado y con letra clara. Resuelva ejercicios diferentes en hojas diferentes. Numere cada hoja, indicando en la primera el total. Coloque su nro. de cédula y nombre en cada hoja. Se permite usar funciones y procedimientos auxiliares en todos los ejercicios, excepto en aquellos en los que se indique lo contrario. Ejercicio 1 (25 puntos) a) Especificar el TAD Árbol Binario de Búsqueda de Naturales (ABNat) en MÓDULA-2. Soluciones (1.a) DEFINITION MODULE ABNat; TYPE ABNat; PROCEDURE CrearABN(): ABNat; (* retorna el arbol vacio *) PROCEDURE ConsABN(a: CARDINAL; Izq,Der: ABNat): ABNat; (* retorna el arbol con raiz a y subarboles izq y der *) PROCEDURE SubIzq(A: ABNat): ABNat; (* retorna el subarbol izquierdo de A pre condicion: A no es vacio *) PROCEDURE SubDer(A: ABNat): ABNat; (* retorna el subarbol derecho de A pre condicion: A no es vacio *) PROCEDURE Raiz(A: ABNat): CARDINAL; (* retorna la raiz de A pre condicion: A no es vacio *) PROCEDURE EsVacioABN(A: ABNat): BOOLEAN; (* retorna TRUE si y solo si A es vacio *) END ABNat. b) Definir un procedimiento ImprimirUnNivelque dado un Árbol Binario de Búsqueda de Naturales y un cardinal k distinto de cero, imprima todos los elementos del árbol que se encuentran en el nivel k, ordenados de mayor a menor. Recordar que la raíz en un árbol binario no vacío se encuentra en el nivel 1. Si el árbol es vacío o k es mayor que la cantidad de niveles del árbol, el procedimiento no tiene efecto. No se permite usar TADs, funciones ni procedimientos auxiliares en este ejercicio. Asuma dada una implementación del TAD ABNat. PROCEDURE ImprimirUnNivel (A: ABNat, k: CARDINAL); Soluciones (1.b) MODULE ImprimirNivel; FROM InOut IMPORT WriteCard; FROM ABNat IMPORT ABNat, EsVacioABN, Raiz, SubDer, SubIzq, ConsABN,CrearABN; PROCEDURE ImprimirUnNivel(A: ABNat; k: CARDINAL); (* precondicion *) BEGIN IF NOT EsVacioABN(A) THEN IF k = 1 THEN WriteCard(Raiz(A),10); ELSE ImprimirUnNivel(SubDer(A),k-1); ImprimirUnNivel(SubIzq(A),k-1); END; END; END ImprimirUnNivel; END ImprimirNivel. Ejercicio 2 (30 puntos) Considerar la siguiente declaración, en MÓDULA-2, del tipo ListaEnt de las listas encadenadas de enteros: ListaEnt = POINTER TO NodoEnt; NodoEnt = RECORD info: INTEGER; sig: ListaEnt; END; Definir una función Ordenarque dada una lista de enteros de tipo ListaEntretorne una lista ordenada, de menor a mayor, que contenga para cada elemento diferente de la lista parámetro la cantidad de veces que ocurre el elemento en dicha lista. Por ejemplo, dada la lista [5, 1, 3, 1, 5, 1, 2], la lista resultado debe ser [(1,3), (2,1), (3,1), (5,2)]. Esto es, el 1 ocurre tres veces, el 2 ocurre una vez, el 3 ocurre una vez y finalmente el 5 ocurre dos veces. No se permite usar TADs en este ejercicio. Soluciones (2) MODULE Lista; FROM Storage IMPORT ALLOCATE; TYPE (* definici'on de lista de naturales *) ListaEnt = POINTER TO NodoEnt; NodoEnt = RECORD info: INTEGER; sig : ListaEnt; END; (* definicion de listas de pares (natural, veces) *) ListaPar = POINTER TO NodoPar; NodoPar = RECORD info: INTEGER; cant: CARDINAL; sig: ListaPar; END; PROCEDURE insertar(x: INTEGER; l: ListaPar): ListaPar; (* l es una lista de pares (info,cant) ordenada por info x es un CARDINAL a ser insertado El resultado es la lista de pares actualizada con el valor x *) VAR p: ListaPar; BEGIN IF (l = NIL) OR (x < l^.info) THEN (* celda nueva al principio *) NEW(p); p^.info:= x; p^.cant:= 1; p^.sig:= l; RETURN p; ELSIF x = l^.info THEN (* incremento contador *) INC(l^.cant); RETURN l; ELSE (* inserci'on en el resto *) l^.sig:= insertar(x,l^.sig); RETURN l; END; END insertar; PROCEDURE ordenar(l: ListaEnt): ListaPar; (* recibe una lista desordenada y retorna una lista de pares ordenada *) BEGIN IF l = NIL THEN RETURN NIL; ELSE RETURN (insertar(l^.info,ordenar(l^.sig))); END; END ordenar; END Lista. Ejercicio 3 (45 puntos) a) Especificar el TAD Cola de Prioridad no acotada de elementos de un tipo genérico T donde las prioridades estén dadas por números naturales, dando un conjunto mínimo de constructoras, selectoras y predicados necesarios. Se requiere que si dos elementos tienen igual prioridad en la cola de prioridad, se respeta la política FIFO (el primero en entrar es el primero en salir). Soluciones (3.a) DEFINITION MODULE PQueue; FROM TipoBase IMPORT T; TYPE PQueue; (*************** Constructoras ***************) PROCEDURE NullPQ () : PQueue; (* Retorna el la cola de prioridad vaci'a *) PROCEDURE InsertPQ (t : T; prio : CARDINAL; PQ : PQueue) : PQueue; (* Retorna una nueva cola de prioridad que consiste de todos los elementos de PQ ma's el elemento t con su prioridad *) (**************** Predicados ****************) PROCEDURE IsEmpty (PQ : PQueue) : BOOLEAN; (* Retorna TRUE si PQ es vaci'a *) (**************** Selectoras ****************) PROCEDURE FindMin(PQ : PQueue) : T; (* Pre: Not IsEmpty(PQ). Retorna el elemento de la cola que posee menor prioridad *) (*************** Destructoras ***************) PROCEDURE DeleteMin(PQ : PQueue) : PQueue; (* Pre: Not IsEmpty(PQ). Retorna la cola PQ sin el elemento de menor prioridad *) END PQueue. b) Desarrollar una implementación del TAD anterior donde para la operación de inserción no se recorran los elementos ya existentes en la Cola de Prioridad. Para las demás operaciones del TAD no hay restricciones. Se debe dar una representación e implementar completamente las operaciones definidas en la parte a). No se permite usar TADs auxiliares en este ejercicio. Soluciones (3.b) IMPLEMENTATION MODULE PQueue; FROM TipoBase IMPORT T; FROM Storage IMPORT ALLOCATE, DEALLOCATE; TYPE (* Se utiliza una lista enlazada simple con celda dummy. La celda dummy se utiliza para simplificar el borrado. Los elementos se insertan al principio tal como vienen. Cuando se pide el elemento con prioridad minima, en caso de existir mas de uno se considera el ultimo (que fue el primero en llegar) *) PQueue = POINTER TO CeldaPQ; CeldaPQ = RECORD info : T; prioridad : CARDINAL; sig : PQueue; END; (*************** Constructoras ***************) PROCEDURE NullPQ () : PQueue; (* Retorna el la cola de prioridad vaci'a *) VAR p: PQueue; BEGIN (* creaci'on de celda dummy *) NEW(p); p^.sig:= NIL; RETURN p; END NullPQ; PROCEDURE InsertPQ (t : T; prio : CARDINAL; PQ : PQueue) : PQueue; (* Retorna una nueva cola de prioridad que consiste de todos los elementos de PQ ma's el elemento t con su prioridad *) VAR p: PQueue; BEGIN NEW(p); p^.info:= t; p^.prioridad:= prio; p^.sig:= PQ^.sig; PQ^.sig:= p; RETURN PQ; END InsertPQ; (**************** Predicados ****************) PROCEDURE IsEmpty (PQ : PQueue) : BOOLEAN; (* Retorna TRUE si PQ es vaci'a *) BEGIN RETURN (PQ^.sig = NIL); END IsEmpty; (**************** Auxiliar ******************) PROCEDURE FindPtrMin(PQ: PQueue): PQueue; (* pre condicion: PQ no vacia Retorna un puntero a la celda anterior al elemento de prioridad minima. Si hay mas de uno retorna el ultimo de ellos. VAR (**** Variables pmin: puntero a la celda anterior al minimo p : puntero auxiliar para recorrer la lista minimo: valor del minimo (es igual a p^.sig^.info *) pmin,p: PQueue; minimo: T; BEGIN (* pongo el primero como minimo *) pmin:= PQ; minimo:= PQ^.sig^.info; p:= PQ^.sig; WHILE p^.sig # NIL DO (* si hay varios minimos me quedo con el ultimo que fue el primero en llegar *) IF p^.sig^.info <= minimo THEN minimo:= p^.sig^.info; pmin:= p; END; p:= p^.sig; END; RETURN pmin; END FindPtrMin; (**************** Selectoras ****************) PROCEDURE FindMin(PQ : PQueue) : T; (* Pre: Not IsEmpty(PQ). Retorna el elemento de la cola que posee menor prioridad *) VAR ptr: PQueue; BEGIN ptr:= FindPtrMin(PQ); RETURN ptr^.sig^.info; END FindMin; (*************** Destructoras ***************) PROCEDURE DeleteMin(PQ : PQueue) : PQueue; (* Pre: Not IsEmpty(PQ). Retorna la cola PQ sin el elemento de menor prioridad *) VAR ptr,pmin: PQueue; BEGIN ptr:= FindPtrMin(PQ); pmin:= ptr^.sig; ptr^.sig:= pmin^.sig; DISPOSE(pmin); RETURN PQ; END DeleteMin; END PQueue.