Instituto de Computación - Facultad de Ingeniería - Universidad de la República Examen de Programación 2 Julio de 2011 Generalidades: • • • • • • • La prueba es individual y sin material; duración: 3hs. 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 (20 puntos) Considere la siguiente declaración, en Módula-2, del tipo de las listas de números enteros LInt: TYPE LInt = POINTER TO RECORD info : INTEGER; sig : LInt END; Se pide, sin usar funciones o procedimientos auxiliares y accediendo directamente a la representación, implementar la siguiente función iterativa: Inv: Dada una lista L de enteros de tipo Lint, retorna una nueva lista (que no comparte registros de memoria con la lista parámetro) que contiene todos los elementos de L, excepto el primero y el último, pero en orden inverso. Si L está vacía la función deberá retornar la lista vacía. Ejemplos: Entradas Resultado de Inv L = [3,2,7,1,8,5] [8,1,7,2] L = [2,4] [] L = [2] [] L = [] [] SOLUCION PROCEDURE Inv ( l : Lint ) : Lint; VAR lstRes, ptrNuevo : Lint; BEGIN lstRes := NIL; IF (l <> NIL) AND (l^.sig <> NIL) THEN l := l^.sig; WHILE (l^.sig <> NIL) DO New(ptrNuevo); ptrNuevo^.info := l^.info; ptrNuevo^.sig := lstRes; lstRes := ptrNuevo; l := l^.sig; END; END; RETURN lstRes; END Inv; Instituto de Computación - Facultad de Ingeniería - Universidad de la República Ejercicio 2. (35 puntos) Para trabajar con árboles balanceados es útil guardar en cada nodo información para verificar condiciones de equilibrio. Por ejemplo, en los árboles llamados AVL (que son ABB balanceados) puede guardarse en cada nodo la altura del árbol que tiene a dicho nodo como raíz. En la siguiente figura se puede ver un ejemplo de la información que poseen los nodos de esta clase de árboles: 6 h=2 h=1 h=0 2 h=3 3 9 4 h=0 h=1 10 h=0 1 Se pide, utilizando la siguiente definición de los árboles binarios de búsqueda de enteros, con información de la altura en cada nodo: ABB = POINTER TO ABBNodo; ABBNodo = RECORD info: INTEGER; altura: CARDINAL; izq, der: ABB; END; a) Implementar un procedimiento que dado un ABB de enteros que guarda en cada nodo, además del dato, el valor de su altura, y dado un entero, inserte a dicho elemento en el ABB (si ya no estaba) manteniendo la información de la altura de cada nodo. Notar que no se pide balancear el árbol, sino simplemente insertar el elemento en el ABB dejando en cada nodo en el campo altura el valor correspondiente, asumiendo que el árbol parámetro guarda en el campo altura de cada nodo el valor correcto. Este procedimiento no puede usar funciones ni procedimientos auxiliares. b) Implemente una función booleana que retorne TRUE si y sólo si un ABB (del tipo definido anteriormente) es un AVL. Esto es, se cumple que para cada nodo del árbol la altura de sus subárboles izquierdo y derecho difiere a lo sumo en 1. El árbol vacío es un AVL. Esta función no puede usar funciones ni procedimientos auxiliares. c) Indique los órdenes de tiempo de ejecución en el peor caso del procedimiento definido en la parte (a) y de la función definida en la parte (b). Justifique brevemente. SOLUCION a) PROCEDURE Insertar (VAR t : ABB; x : INTEGER); BEGIN IF (t = NIL) THEN NEW(t); t^.info := x; t^.altura := 0; t^.izq := NIL; t^.der := NIL ELSIF (x < t^.info) THEN Insertar(t^.izq, x); Instituto de Computación - Facultad de Ingeniería - Universidad de la República IF (t^.altura = t^.izq^.altura) THEN t^.altura := t^.altura + 1 END ELSIF (x > t^.info) THEN Insertar(t^.der, x); IF (t^.altura = t^.der^.altura) THEN t^.altura := t^.altura + 1 END END END Insertar; b) PROCEDURE EsAVL (t : ABB) : BOOLEAN; BEGIN IF (t = NIL) OR ((t^.izq = NIL) AND (t^.der = NIL)) THEN RETURN TRUE ELSIF (t^.izq = NIL) THEN RETURN (t^.der^.altura = 0) ELSIF (t^.der = NIL) THEN RETURN (t^.izq^.altura = 0) ELSE RETURN (ABS(t^.izq^.altura – t^.der^.altura) <= 1) AND EsAVL(t^.izq) AND EsAVL(t^.der) END END EsAVL; c) El procedimiento Insertar es O(n) de tiempo de ejecución en el peor caso, siendo n la cantidad de nodos del árbol. El peor caso se da cuando la inserción se produce en un camino que tiene a todos los nodos del árbol (el árbol degenera en una lista). La función EsAVL es O(n) de tiempo de ejecución en el peor caso, siendo n la cantidad de nodos del árbol. La función recorre todo el árbol y si éste es efectivamente un AVL, todos los nodos serán visitados (considerados) una vez. Ejercicio 3. (45 puntos) a) De una especificación de un TAD Cola de Prioridad no acotada de elementos de un tipo genérico T donde las prioridades estén dadas por números naturales y que permita obtener, y eliminar, elementos tanto de mínima como de máxima prioridad. Considere un conjunto mínimo de operaciones constructoras, selectoras/destructoras (Min, BorrarMin, Max, BorrarMax) y predicados. Tenga en cuenta que pueden haber elementos de igual prioridad y que las operaciones selectoras/destructoras consideran el orden de llegada frente a elementos de igual prioridad. b) Desarrolle una implementación del TAD anterior donde las operaciones selectoras Min y Max, las operaciones constructoras y los predicados tengan O(1) de tiempo de ejecución en el peor caso. Se debe dar una representación e implementar las operaciones constructoras, las selectoras/destructoras Min y BorrarMin, y los predicados. Omita el código de Max y Borrar Max. No se permite usar TADs auxiliares en este ejercicio. c) ¿Qué varía en la especificación de la parte a) si la Cola de Prioridad es acotada?. Detalle brevemente. ¿Qué varía en la implementación de la parte b) si la Cola de Prioridad es acotada y se debe satisfacer igualmente la restricción de orden de tiempo de ejecución impuesta a ciertas operaciones del TAD?. Detalle brevemente (no se pide desarrollar código). d) Dos Colas de Prioridad son iguales si son indistinguibles a través de sus operaciones selectoras/destructoras. Desarrolle una función que dadas dos Colas de Prioridad de acuerdo a la especificación dada en la parte a), retorne TRUE si y sólo si éstas son iguales. Asuma que los elementos de tipo T son comparables con el operador “=”. La función puede modificar las colas de prioridad parámetros. Instituto de Computación - Facultad de Ingeniería - Universidad de la República SOLUCION a) PROCEDURE EmptyPQ (VAR pq: PQ); (* Construye la cola de prioridad vacía *) PROCEDURE IsEmptyPQ (pq: PQ; VAR empty: Boolean); (* Retorna TRUE si pq es vacía y FALSE en caso contrario *) PROCEDURE InsertPQ (t: T; p: Cardinal; VAR pq: PQ); (* Inserta el elemento t con prioridad p en la cola pq *) PROCEDURE Min (pq: PQ; VAR min: T); (* PRE: NOT IsEmpty(pq). Retorna el elemento de pq con prioridad mínima, teniendo en cuenta el orden FIFO en caso de elementos de igual prioridad *) PROCEDURE Max (pq: PQ; VAR max: T); (* PRE: NOT IsEmpty(pq). Retorna el elemento de pq con prioridad máxima, teniendo en cuenta el orden FIFO en caso de elementos de igual prioridad *) PROCEDURE BorrarMin (VAR pq: PQ); (* PRE: NOT IsEmpty(pq). Elimina de pq el elemento con prioridad mínima, teniendo en cuenta el orden FIFO en caso de elementos de igual prioridad *) PROCEDURE BorrarMax (VAR pq: PQ); (* PRE: NOT IsEmpty(pq). Elimina de pq el elemento con prioridad máxima, teniendo en cuenta el orden FIFO en caso de elementos de igual prioridad *) (* Podría incluirse una destructora del TAD que libere toda la memoria de una cola de prioridad. En este caso la omitimos asumiendo que puede definirse por fuera del TAD a partir de las existentes *) b) (* Lista simplemente encadenada con punteros al mínimo y máximo, teniendo en cuenta el orden FIFO en caso de elementos de igual prioridad. Las inserciones se realizan siempre al comienzo de la lista. *) TYPE List = POINTER TO ListNode; ListNode = RECORD value: T; prior: CARDINAL; sig: List; END; PQ = POINTER TO PQNode; PQNode = RECORD min, max: List; values: List; END; PROCEDURE EmptyPQ BEGIN NEW(pq); pq^.min := pq^.max := pq^.values END EmptyPQ; (VAR pq : PQ); NIL; NIL; := NIL; PROCEDURE IsEmptyPQ (pq: PQ; VAR empty: Boolean); BEGIN empty := (pq^.values = NIL); END IsEmptyPQ; Instituto de Computación - Facultad de Ingeniería - Universidad de la República PROCEDURE InsertPQ (t: T; p: Cardinal; VAR pq: PQ); VAR elem : List; BEGIN NEW(elem); elem^.value := t; elem^.prior := p; elem^.sig := pq^.values; pq^.values := elem; (* mantengo el orden de los repetidos según la política FIFO *) IF ((pq^.min = NIL) OR (pq^.min^.prior > p)) THEN pq^.min = elem; END; (* mantengo el orden de los repetidos según la política FIFO *) IF ((pq^.max = NIL) OR (pq^.max^.prior < p)) THEN pq^.max = elem; END; END; PROCEDURE Min (pq: PQ; VAR min: T); BEGIN min := pq^.min^.value; END Min; (* Auxiliar de BorrarMin *) PROCEDURE BorrarNodoMin (VAR pq: PQ); (* PRE: NOT IsEmpty(pq). Elimina de pq el nodo con el elemento de prioridad mínima, teniendo en cuenta el orden FIFO en caso de elementos de igual prioridad. pq^.min y eventualmente pq^.max quedan indefinidos *) VAR lista: List; BEGIN lista := pq^.values; IF (pq^.min = lista) THEN (* Si es el primero *) pq^.values := pq^.values^.sig; ELSE WHILE (lista^.sig <> pq^.min) DO lista := lista^.sig; END; lista^.sig := lista^.sig^.sig; END; DISPOSE(pq^.min); END BorrarNodoMin; (* Auxiliar de BorrarMin *) PROCEDURE EstablecerMinMax (VAR pq: PQ); (* Establece los punteros a los elementos de prioridad mínima y máxima de pq, teniendo en cuenta el orden FIFO en caso de elementos de igual prioridad *) VAR lista, PunteroMin, PunteroMax: List; BEGIN lista := pq^.values; PunteroMin:= lista; PunteroMax:= lista; WHILE (lista <> NIL) DO IF (lista^.prior <= PunteroMin^.prior) THEN PunteroMin := lista; END; IF (lista^.prior >= PunteroMax^.prior) THEN PunteroMax := lista; END; lista := lista^.sig; END; pq^.min := PunteroMin; pq^.max := PunteroMax; END EstablecerMinMax; Instituto de Computación - Facultad de Ingeniería - Universidad de la República PROCEDURE BorrarMin (VAR pq : PQ); BEGIN BorrarNodoMin(pq); EstablecerMinMax(pq); END BorrarMin; c) Parte i) • • Requiere agregar un predicado que permita saber si la PQ está llena. PROCEDURE IsFullPQ (pq: PQ; VAR full: Boolean); (* Retorna TRUE si pq esta llena y FALSE en caso contrario *) Requiere agregar la siguiente precondición al procedimiento InsertPQ: PRE: NOT IsFull(pq). Parte ii) • Requiere incorporar en la estructura un contador para saber cuantos elementos hay y evitar de esta manera tener que recorrer la estructura en el código del procedimiento IsFullPQ. d) PROCEDURE Iguales(pq1, pq2: PQ) : BOOLEAN; VAR e1, e2 : BOOLEAN; min1, min2 : T; BEGIN IsEmptyPQ(pq1, e1); IsEmptyPQ(pq1, e2); IF (e1 AND e2) THEN RETURN TRUE; ELSIF (NOT(e1) AND NOT(e2)) THEN Min(pq1, min1); Min(pq2, min2); BorrarMin(pq1); BorrarMin(pq2); RETURN ((min1 = min2) AND Iguales(pq1, pq2)); ELSE RETURN FALSE; END; END Iguales;