Solución de Examen de Programación 2 Diciembre de 2013 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. Ejercicio 1 ( 50 puntos) Considere las siguientes definiciones: TYPE ListaNat = POINTER TO LNodo; LNodo = RECORD elem: CARDINAL; sig: ListaNat; END; ABNat ABNodo = POINTER TO ABNodo; = RECORD nodo: CARDINAL; izq,der: ABNat; END; Implemente en Modula-2 y utilizando recursión las siguientes funciones: 1. Una función InsOrd, que dados un natural y una lista ListaNat ordenada (creciente) inserte el natural en la lista manteniendo su orden. La lista resultante comparte memoria con la lista pasada como parámetro. PROCEDURE InsOrd (e : CARDINAL; l : ListaNat): ListaNat; 2. Una función GenerarListaOrd, que dado un árbol binario de naturales ABNat retorne una lista ListaNat ordenada (creciente) con todos los elementos del árbol. No se puede acceder a la estructura de la lista, para construirla sólo se puede utilizar NIL (lista vacía) y la función de la parte anterior. PROCEDURE GenerarListaOrd (a : ABNat): ListaNat; 3. Una función Ordenar, que dado un árbol binario de naturales ABNat retorne otro árbol que tenga la misma forma y los mismos elementos, pero que sea un árbol binario de búsqueda. El árbol resultante no comparte memoria con el árbol pasado como parámetro. Si utiliza funciones auxiliares debe implementarlas. PROCEDURE Ordenar (a : ABNat): ABNat; NOTA: en caso de utilizarse funciones auxiliares estas deben ser implementadas Ejercicio 2 (50 puntos) Se desea utilizar una Tabla para guardar información de contactos telefónicos en forma de correspondencias entre Nombres y Télefonos. Los Nombres y los Teléfonos son cadenas de caracteres que pueden representarse con el tipo STRING. 1. Especifique, en MODULA-2, un TAD TablaContactos con operaciones constructoras, selectoras/destructoras y predicados, que permita guardar una cantidad no conocida a priori de Nombres y Télefonos. Además de las operaciones habituales de Tabla se necesita contar con una operación llamada ListarTodosOrdenados que recibe una TablaContactos e imprime todos los contactos en orden alfabético por Nombre, en forma de líneas que contienen cada una Nombre y Télefono. 2. Implemente el TAD TablaContactos teniendo en cuenta que las operaciones de inserción deben ejecutarse en orden log2(n) en caso promedio, siendo n la cantidad de elementos que contiene la TablaContactos. Provea una representación para este TAD y el código de las operaciones constructoras y de ListarTodosOrdenados. Omita el código del resto de las operaciones del TAD. Se permite utilizar las operaciones <, >, = y <> para comparar STRINGs. 3. Considere que se quiere modificar el TAD TablaContactos, agregando la funcionalidad de discado rápido que permita almacenar hasta K referencias a contactos. Esta funcionalidad se implementa mediante las siguientes operaciones: PROCEDURE InicializarLDRapido (VAR T: TablaContactos); (* Inicializa el discado rápido en la TablaContactos T *) PROCEDURE InsertarLDRapido (VAR T: TablaContactos; nomContacto: STRING; j: STRING); (* Inserta en la posición j<=K del discado rápido de T una referencia al contacto ya existente en T con nombre=nomContacto *) PROCEDURE BusquedaRapida (T: TablaContactos; j: CARDINAL); (* Imprime el teléfono y nombre del contacto almacenado en la posición j<=K discado rápido de T *) del Se pide: a) Modifique la representación del TAD que propuso como solución a la parte 2 de forma de permitir resolver la operación BusquedaRapida en O(1). b) Implemente InicializarLDRapido, InsertarLDRapido y BusquedaRapida. Solución ejercicio 1 Parte 1 PROCEDURE InsOrd (e : CARDINAL; l : ListaNat): ListaNat; VAR res : ListaNat; BEGIN IF (l = NIL) OR (l^.elem > e) THEN NEW (res); res^.elem := e; res^.sig := l ELSE res := l; res^.sig := InsOrd(e,l^.sig) END; RETURN res END InsOrd; Parte 2 PROCEDURE GenerarRec (a : ABNat; VAR res : ListaNat); BEGIN IF a # NIL THEN res := InsOrd(a^.nodo,res); GenerarRec(a^.izq,res); GenerarRec(a^.der,res) END END GenerarRec; PROCEDURE GenerarListaOrd (a : ABNat): ListaNat; VAR res : ListaNat; BEGIN res := NIL; GenerarRec(a,res); RETURN res END GenerarListaOrd; Parte 3 PROCEDURE OrdenarRec (a : ABNat; VAR l : ListaNat): ABNat; VAR res : ABNat; laux : ListaNat; BEGIN res := NIL; IF a # NIL THEN NEW (res); res^.izq := OrdenarRec(a^.izq,l); res^.nodo := l^.elem; laux := l; l := l^.sig; DISPOSE(laux); res^.der := OrdenarRec(a^.der,l) END; RETURN res END OrdenarRec; PROCEDURE Ordenar (a : ABNat): ABNat; VAR l : ListaNat; BEGIN l := GenerarListaOrd(a); RETURN OrdenarRec(a,l) END Ordenar; Solución ejercicio 2 Parte 1 PROCEDURE CreoTabla (): TablaContactos; (* retorna la tabla vacía *) PROCEDURE Insertar (d: STRING; r: STRING; VAR T: TablaContactos); (* Define T(d) = r, independientemente de que T(d) estuviera ya definido *) PROCEDURE EsVacia (T: TablaContactos): BOOLEAN (* retorna TRUE sii T es vacía *) PROCEDURE EstaDefinida (T: TablaContactos; d: STRING): BOOLEAN (* retorna TRUE sii T está definida para d *) PROCEDURE Recuperar(d: STRING; T: TablaContactos; VAR r: STRING); (* retorna r si EstaDefinida(d)=TRUE y r = T(d) *) PROCEDURE Borrar(d: STRING; VAR T: TablaContactos); (* elimina la correspondencia que vincula a d en T. Luego de borrar, EstaDefinida(T,d) es FALSE *) PROCEDURE ListarTodosOrdenados (T: TablaContactos); (* imprime todos los contactos en orden alfabético por Nombre, en forma de líneas que contienen cada una: Nombre, Télefono. *) Parte 2 La representación es un ABB, de este modo la operación Insertar tiene orden de ejecución logarítmico en caso promedio. TYPE TablaContactos = POINTER TO TCNodo; TCNodo = RECORD nom, tel: STRING; izq, der: TablaContactos; END; PROCEDURE CreoTabla (): TablaContactos; BEGIN RETURN NIL; END CreoTabla; PROCEDURE Insertar (d: STRING; r: STRING; VAR T: TablaContactos); (* Define T(d) = r, independientemente de que T(d) estuviera ya definido *) BEGIN IF (T=NIL) THEN NEW(T); T^.nom:=d; T^.tel:=t; T^.izq:=NIL; T^.der:=NL; ELSEIF (T^.nom=d) THEN T^.tel:=t; ELSEIF (T^.nom>d) THEN Insertar (d, r, T^.izq); ELSE Insertar (d, r, T^.der); END; END Insertar; PROCEDURE ListarTodosOrdenados (T: TablaContactos); (* imprime todos los contactos en orden alfabético por Nombre, en forma de líneas que contienen cada una: Nombre, Télefono. *) BEGIN IF (T<>NIL) THEN ListarTodosOrdenados(T^.izq); WriteString(T^.nom); WriteString(' ;'); WriteString(T^.tel); WriteLn; ListarTodosOrdenados(T^.der); END; END ListarTodosOrdenados; Parte 3 Se agrega al tipo un arreglo de largo K de punteros a nodos del árbol. De esta forma dada una posición j con 1<=j<=k se puede obtener en O(1) los datos del registro en esa posición. TYPE PTC= POINTER TO TCNodo; TCNodo = RECORD nom, tel: STRING; izq, der: PTC; END; TablaContactos = RECORD tablaC: PTC; busRap : ARRAY[1..K] OF PTC; END; PROCEDURE InicializarLDRapido (VAR T: TablaContactos); (* Pre: T es una TablaContactos y T(n). Pos: inserta una referencia a NIL para todos los lugares de la lista de discado rápido independientemente de lo que hubiera antes. *) VAR j: PTC; BEGIN FOR j:=1 TO K DO T^.busRap[j]:=NIL; END; END InicializarLDRapido; PROCEDURE InsertarLDRapido (VAR T: TablaContactos; n: STRING; j: CARDINAL); (* Pre: j<=K, T es una TablaContactos y T(n) esta definido en tc. Pos: inserta una referencia a n y T(n) en el lugar j de la lista de discado rápido independientemente de lo que hubiera antes. *) VAR tc: PTC; BEGIN tc:= T^.tablaC; WHILE (tc^.nom<>n) DO IF (tc^.nom>n) THEN tc:= tc^.der; ELSE tc:= tc^.izq; END; T^.busRap[j]:=tc; END InsertarLDRapido; PROCEDURE BusquedaRapida (T: TablaContactos; j: CARDINAL); (* Pre: j<=K y T es una TablaContactos. Pos: imprime el Nombre y Télefono de la persona ubicada en el lugar j de la lista de discado rápido o NIL en caso de que j no esté definido en la lista de discado rápido. *) BEGIN WriteString(T^.busRap[j]^.nom); WriteString(' ;'); WriteString(T^.busRap[j]^.tel); WriteLn; END BusquedaRapida;