Instituto de Computación - Facultad de Ingeniería - Universidad de la República Parcial de Programación 2 14 de Julio de 2014 Generalidades: • La prueba es individual y sin material. • Resuelva ejercicios diferentes en hojas diferentes. • Duración: 3:30hs. • Numere cada hoja, indicando en la primera el total. • Sólo se contestan dudas acerca de la letra. • Escriba su número de cédula y nombre en cada hoja. • Escriba las hojas de un sólo lado y con letra clara. • Escriba el código en Modula-2. Ejercicio 1 (22 puntos) Se desea modelar un TAD Urna que permita registrar votos a diferentes candidatos. Las operaciones con las que debe contar el TAD son las siguientes: • UrnaVacia, que crea una Urna vacía. • InsertarVoto, que recibe un candidato y una Urna, y agrega a la Urna un voto para ese candidato. • CantVotos, que recibe un candidato y una Urna, y devuelve la cantidad de votos para ese candidato que están en la Urna. a) Escriba una especificación procedural del TAD Urna no acotado descripto anteriormente. Asuma que los candidatos son de tipo String. b) Desarrolle una implementación del TAD Urna especificado en la parte (a), de forma que InsertarVoto sea O(1) en peor caso. c) Indique para cada una de las tres operaciones implementadas en la parte (b) cuál es el orden de tiempo de ejecución en el peor caso. Justifique brevemente. d) Si sabe que hay n candidatos y que cada uno de ellos puede identificarse con un número en el rango [1,n], explique qué implementación permitiría que las operaciones InsertarVoto y CantVotos sean O(1) en peor caso. ¿Cuál sería el orden de tiempo de ejecución en ese caso de la operación UrnaVacia? Solución: a) DEFINITION MODULE Urna TYPE Urna; PROCEDURE UrnaVacia (VAR u: Urna); (* Retorna la urna vacía en la variable u. *) PROCEDURE InsertarVoto (c: String; VAR u: Urna); (* Agrega un voto al candidato c en la urna u. *) PROCEDURE CantVotos (c: String; u: Urna; VAR cant: CARDINAL); (* Devuelve la cantidad de votos del candidato c en la variable *) (* cant. *) END Urna; 1/6 Instituto de Computación - Facultad de Ingeniería - Universidad de la República b) TYPE Urna = NodoUrna = POINTER TO NodoUrna; RECORD voto: String; sig: Urna; END; PROCEDURE UrnaVacia (VAR u: Urna) BEGIN u := NIL END VaciarUrna; PROCEDURE InsertarVoto (c: String; VAR u: Urna) VAR auxUrna: Urna; BEGIN NEW(auxUrna); auxUrna^.voto := c; auxUrna^.sig := u; u := auxUrna END InsertarVoto; PROCEDURE CantVotos (c: String; u: Urna; VAR cant: CARDINAL) BEGIN cant := 0; WHILE (u <> NIL) DO IF (u^.voto = c) THEN cant := cant + 1 END; u := u^.sig END END CantVotos; 2/6 Instituto de Computación - Facultad de Ingeniería - Universidad de la República c) • • • UrnaVacia La operación es de orden 1 ya que se trata de una asignación. InsertarVoto Tal cual se pide en la letra la operación es de orden 1. Esto se debe a que se inserta un elemento al principio de una lista. Como se tiene la referencia a esta posición por definición de la estructura simplemente se debe crear el nuevo nodo y apuntar el siguiente a la lista que ya se tenía. CantVotos Debido a que la urna es una lista de votos, es necesario recorrer toda la lista para saber la cantidad de votos para cada candidato. Por lo tanto el orden de esta operación es n. d) Aprovechando que se tiene el mapeo de los candidatos con un número en el rango [1,n] se puede utilizar una implementación con un arreglo de enteros como estructura de datos para representar la urna. El valor almacenado en cada celda del arreglo sería la cantidad de votos del candidato al que está asociado. Como la búsqueda de los elementos en ese arreglo sería de orden 1 (la celda i del arreglo representa al candidato i, para todo i perteneciente al rango [1,n]), las operaciones InsertarVoto y CantVotos cumplirían con la restricción. La operación UrnaVacia deberá inicializar en 0 los valores de cada candidato. Por lo tanto es necesario recorrer todo el arreglo, lo que hace que esta operación sea de orden n. Ejercicio 2 (10 puntos) Dado el tipo Arbol23 para representar árboles 2-3 de naturales: TYPE Arbol23 = POINTER TO Nodo; TipoNodo = (Nodo2,Nodo3); Nodo = RECORD CASE tipo : TipoNodo OF Nodo2 : val : CARDINAL; | Nodo3 : valIzq, valDer : CARDINAL; hijoMedio : Arbol23; END; hijoIzq, hijoDer : Arbol23; END; Accediendo a dicha representación, y aprovechando las propiedades de los árboles 2-3, implemente la operación de búsqueda con O(log n) peor caso: PROCEDURE Pertenece (elem: CARDINAL; arbol: Arbol23): BOOLEAN; Solución: • • • Cada nodo tiene entre 2 y 3 hijos. Todas las hojas están al mismo nivel. Se cumple que si un nodo tiene n hijos, entonces el nodo tiene n-1 3/6 Instituto de Computación - Facultad de Ingeniería - Universidad de la República • claves. La propiedad de orden es la siguiente: ◦ Si el nodo tiene 2 hojas, la rama izquierda contendrá valores menores a la clave en la raíz y la derecha mayores. ◦ Si el nodo tiene 3 hojas, la rama izquierda contendrá valores menores a las dos claves en la raíz, la rama del medio tiene valores mayores a la clave izquierda y menores a la clave derecha y la rama derecha tiene los valores mayores a las dos claves. Por lo tanto la búsqueda se puede implementar: PROCEDURE Pertenece (elem: CARDINAL; arbol: Arbol23): BOOLEAN BEGIN IF (arbol = NIL) THEN RETURN FALSE ELSE IF (arbol^.tipo = Nodo2) THEN IF (arbol^.val = elem) THEN RETURN TRUE ELSE IF (arbol^.val > elem) THEN RETURN Pertenece(elem,arbol^.hijoIzq) ELSE RETURN Pertenece(elem,arbol^.hijoDer) END END ELSE IF ((arbol^.valIzq = elem) OR (arbol^.valDer = elem)) THEN RETURN TRUE ELSE IF (arbol^.valIzq > elem) THEN RETURN Pertenece(elem,arbol^.hijoIzq) ELSIF (arbol^.valDer > elem) THEN RETURN Pertenece(elem,arbol^.hijoMedio) ELSE RETURN Pertenece(elem,arbol^.hijoDer) END END END END END Pertenece; 4/6 Instituto de Computación - Facultad de Ingeniería - Universidad de la República Ejercicio 3 (28 puntos) Suponga que se quiere determinar cuáles son las palabras que más aparecen en un texto. Dicho texto se encuentra representado como una lista de pares (palabra, cantidad), donde palabra representa una palabra del texto y cantidad es la cantidad de veces que dicha palabra aparece en el texto. Se cuenta con el tipo Contador para representar los pares (palabra, cantidad), y con un TAD ListaContador con las operaciones usuales del TAD Lista (recuerde que la inserción se hace al comienzo). Asuma la siguiente definición del tipo Contador: TYPE Contador = RECORD palabra :String; cantidad: CARDINAL; END; Se quiere implementar una función ListarKMasFrecuentes, que dados un texto representado con el TAD ListaContador y un entero k, devuelve una ListaContador con los k pares (palabra, cantidad) que corresponden a las k palabras más frecuentes en el texto. Estos pares se devuelven ordenados en forma decreciente según cantidad de apariciones. No hay un criterio de desempate preestablecido en caso de empates en la cantidad de apariciones, quedando esto librado a la implementación. Si k es mayor que el largo de la lista que representa el texto, se devuelven todas las palabras del texto. El encabezado de la función ListarKMasFrecuentes es el siguiente: PROCEDURE ListarMasFrecuentes (lst: ListaContador; k: CARDINAL): ListaContador; A continuación se presentan ejemplos: lst =[(quiero,3),(doy,2),(tengo,3),(yo,5),(necesito,3)] ListarKMasFrecuentes(lst,0)= [] ListarKMasFrecuentes(lst,1)= [(yo,5)] ListarKMasFrecuentes(lst,2)= [(yo,5),(quiero,3)] o [(yo,5),(tengo,3)] o [(yo,5),(necesito,3)] a) Especifique el TAD Cola de Prioridad acotada de elementos del tipo Contador, donde un elemento tiene más prioridad que otro si el valor de su campo cantidad es menor. El tamaño de la Cola de Prioridad se define al momento de crearla. Incluya pre y post condiciones. b) Implemente ListarKMasFrecuentes usando una Cola de Prioridad auxiliar de tamaño k con las operaciones especificadas en (a) y las del TAD ListaContador. La lista original lst se puede recorrer una sola vez. c) Suponiendo que k es acotado por una constante MAX_K ¿cuál de las implementaciones, vistas en el curso, para el TAD de la parte (a) es la más eficiente en tiempo de ejecución? Describa propiedades y tiempos de ejecución en el peor caso para cada una de las operaciones especificadas. Solución: a) PROCEDURE NuevaCPrio (tamaño: CARDINAL): ColaPrioridad; (* Devuelve una ColaPrioridad vacía de tamaño 'tamaño'. *) PROCEDURE InsertarCPrio (cont: Contador; VAR cp: ColaPrioridad); (* Precondicion: 'cp' no está llena. Inserta 'cont' en 'cp' con prioridad 'cont.cantidad'. *) (************ Selectoras ****************) PROCEDURE MinimoCPrio (cp: ColaPrioridad): Contador; (* Precondición: 'cp' no está vacía. Devuelve el Contador de 'cp' que tiene asociado el menor valor 5/6 Instituto de Computación - Facultad de Ingeniería - Universidad de la República de cantidad, o sea, el de mayor prioridad. *) (************ Predicados *************) PROCEDURE EsVaciaCPrio (cp: ColaPrioridad): BOOLEAN; (* Devuelve TRUE si 'cp' no tiene elementos, FALSE en otro caso. *) PROCEDURE EsLlenaCPrio (cp: ColaPrioridad): BOOLEAN; (* Devuelve TRUE si 'cp' tiene 'tamaño' elementos, FALSE en otro caso, siendo 'tamaño' el parámetro pasado en la creación de 'cp'. *) (************ Destructoras *************) PROCEDURE EliminarMinCPrio (VAR cp: ColaPrioridad); (* Precondición: 'cp' no está vacía. Elimina de 'cp' el Contador que tiene asociado el menor valor de cantidad. *) b)PROCEDURE ListaKMasFrecuentes (lst: ListaContador, k:CARDINAL): ListaContador VAR cp:ColaPrioridad; elem, elemMinimo:Contador; lResultado:listaContador; BEGIN cp := NuevaCPrio (k); WHILE (NOT EsVacia(lst)) DO elem := Cabeza(lst); lst := Cola(lst); IF (NOT EsLlenaCPrio(cp)) THEN InsertarCPrio (elem, cp) ELSE elemMinimo := MinimoCPrio(cp); IF (elem.cantidad > elemMinimo.cantidad) THEN EliminarMinCPrio(cp); InsertarCPrio(elem,cp) END END END; lResultado:=Vacia(); WHILE (NOT EsVaciaCPrio(cp)) DO Cons(MinimoCPrio(cp),lResultado); EliminarMinCPrio(cp) END; RETURN lResultado END ListaKMasFrecuentes; c) Dado que k es acotado y que no hay obligaciones con respecto a la forma de decidir el mínimo cuando hay empates, resulta que la más eficiente en tiempos de ejecución de la implementaciones vistas en el curso es la de heap implementado con un arreglo. Se detallan a continuación los tiempos de ejecución de cada una de sus operaciones: InsertarCPrio (cont: Contador; VAR cp: ColaPrioridad) - log(n) MinimoCPrio (cp: ColaPrioridad): CONTADOR - O(1) EsVaciaCPrio (cp: ColaPrioridad): BOOLEAN - O(1) EsLlenaCPrio (cp: ColaPrioridad): BOOLEAN – O(1) EliminarMinCPrio (VAR cp: ColaPrioridad) - log(n) 6/6