Parcial de Programación 2, mayo 2003

Anuncio
Parcial de Programación 2
10 de Julio de 2015
Generalidades:

La prueba es individual y sin material.

Escriba las hojas de un sólo lado y con letra clara.

La duración es 3hs.

Numere cada hoja, indicando en la primera el total.

Sólo se contestan dudas acerca de la letra.

Coloque su nro. de cédula y nombre en cada hoja.
Ejercicio 1 (30 puntos)
Considere el TAD Pedidos de elementos, de un tipo arbitrario E, que admite el ingreso de elementos de dos formas:
normal y urgente.
La política de egreso de elementos sigue el siguiente orden: primero se atienden los elementos que se insertaron de
forma urgente y luego los que se insertaron de manera normal.
Si se insertaron dos o más elementos de forma urgente, se atiende primero al más recientemente insertado.
Los elementos insertados de forma normal se atienden solo si no hay elementos ingresados de forma urgente. En
este caso, los elementos son atendidos siguiendo el orden de llegada (se atiende primero al que ingresó primero).
Se pide:
a) Escriba una especificación del TAD Pedidos, no acotado, de elementos de un tipo arbitrario E que incluya
operaciones para: crear el TAD vacío; insertar un elemento de forma urgente; insertar un elemento de
forma normal; saber si el TAD está vacío; conocer la cantidad de elementos presentes en el TAD que
fueron insertados de forma urgente; obtener y al mismo tiempo remover el elemento que debe ser atendido,
respetando la política de egreso definida previamente.
b) Implemente el TAD Pedidos (sin usar TADs auxiliares) de tal manera que todas las operaciones tengan
O(1) de tiempo de ejecución en el peor caso.
Solución
a) DEFINITION MODULE Pedidos;
TYPE Pedidos;
PROCEDURE VacioPedidos(): Pedidos;
(* Crea una estructura de pedidos vacía. *)
PROCEDURE InsertarUrgente (elem: E; VAR p: Pedidos);
(* Inserta el elemento 'elem' en la estructura 'p' de tal forma que
esté representado como urgente. *)
PROCEDURE InsertarNormal (elem: E; VAR p: Pedidos);
(* Inserta el elemento 'elem' en la estructura 'p' de tal forma que
esté representado como normal. *)
PROCEDURE EsVacioPedidos (p: Pedidos): BOOLEAN
(* Retorna TRUE si 'p' está vacío. De lo contrario, retorna FALSE. *)
PROCEDURE CantidadUrgentes (p: Pedidos): CARDINAL
(* Retorna la cantidad de pedidos urgentes que tiene 'p'. *)
PROCEDURE ObtenerSiguiente (VAR p: Pedidos): E
(* PRECONDICIÓN: NOT EsVacioPedidos(p)
Retorna el siguiente elemento a atender y lo elimina de 'p', considerando el
siguiente orden: primero se atienden los elementos que se insertaron de forma
urgente y luego los que se insertaron de manera normal. Si se insertaron dos o
más elementos de forma urgente, se atiende primero al más recientemente
insertado (LIFO). Los elementos insertados de forma normal se atienden solo si
no hay elementos ingresados de forma urgente. En este caso, los elementos son
atendidos siguiendo el orden de llegada (FIFO). *)
END Pedidos;
b) REPRESENTACIÓN
IMPLEMENTATION MODULE Pedidos;
Lista = POINTER TO RECORD
info: E;
sig: Lista;
END;
Pedidos = POINTER TO
inicio:
fin:
cantU:
END;
RECORD
Lista;
Lista;
CARDINAL;
PROCEDURE VacioPedidos (): Pedidos;
VAR
retorno: Pedidos;
BEGIN
NEW (retorno);
NEW (retorno^.inicio);
(* Se usa un nodo cabecera (celda dummy) en la representación *)
retorno^.inicio^.sig := NIL;
retorno^.fin := retorno^.inicio;
retorno^.cantU := 0;
RETURN retorno;
END VacioPedidos;
PROCEDURE InsertarUrgente (elem: E; VAR p: Pedidos);
VAR
nuevo: Lista;
BEGIN
NEW (nuevo);
nuevo^.info := elem;
nuevo^.sig := p^.inicio^.sig;
p^.inicio^.sig := nuevo;
INC (p^.cantU);
END InsertarUrgente;
PROCEDURE InsertarNormal (elem: E; VAR p: Pedidos);
BEGIN
NEW (p^.fin^.sig);
p^.fin := p^.fin^.sig;
p^.fin^.info := elem;
p^.fin^.sig := NIL;
END InsertarNormal;
PROCEDURE EsVacioPedidos (p: Pedidos): BOOLEAN;
BEGIN
RETURN p^.inicio^.sig = NIL;
END EsVacioPedidos;
PROCEDURE CantidadUrgentes (p: Pedidos): CARDINAL;
BEGIN
RETURN p^.cantU;
END CantidadUrgentes;
PROCEDURE ObtenerSiguiente (VAR p: Pedidos): E;
VAR
proximo: Lista;
retorno: E;
BEGIN
proximo := p^.inicio^.sig;
retorno := proximo^.info;
p^.inicio^.sig := proximo^.sig;
IF p^.cantU > 0 THEN
DEC (p^.cantU);
END;
DISPOSE (proximo);
RETURN retorno;
END ObtenerSiguiente;
END Pedidos;
Ejercicio 2 (30 puntos)
Una Universidad decide cada año cuáles van a ser los cursos de verano (identificados con un código alfanumérico
representado por un String) que se dictarán. Una vez que se sabe cuáles son y el total T, se habilitan las
inscripciones por parte de los estudiantes (quienes se identifican con un String). No hay límite en la cantidad de
inscriptos a cada curso y cada estudiante puede inscribirse a todos los cursos que quiere.
Se define un TAD Inscripciones para registrar las inscripciones de los estudiantes a cursos, cuyas operaciones son
(todos los órdenes indicados son para el peor caso):
PROCEDURE CrearInscripciones (VAR i: Inscripciones);
(* Crea una colección de inscripciones vacía.
El tiempo de ejecución debe ser O(1). *)
PROCEDURE EsVacioInscripciones (i: Inscripciones): BOOLEAN;
(* Retorna TRUE si y solo si la colección de inscripciones es vacía.
El tiempo de ejecución debe ser O(1). *)
PROCEDURE InscripcionesCurso (c: String; e: Pila; VAR i: Inscripciones);
(* Precondición: En 'i' NO hay inscriptos al curso 'c'.
Ingresa en 'i' las inscripciones al curso 'c' de los estudiantes contenidos
en la Pila de Strings 'e'. La pila contiene los nombres de los estudiantes
y está en orden cronológico decreciente de inscripción; es decir que
el último que se inscribió está en el tope de la pila.
El tiempo de ejecución debe ser O(log t), siendo t <= T la cantidad de
cursos que tienen inscripciones registradas. *)
PROCEDURE InscriptosCursoMayorCodigo (i: Inscripciones): Pila;
(* Devuelve la pila de Strings que contiene los nombres de los estudiantes
inscriptos al curso de mayor código en orden lexicográfico. La pila está en
orden cronológico decreciente de inscripciones.
El tiempo de ejecución debe ser O(1). *)
PROCEDURE ObtenerInscripciones (VAR i: Inscripciones): Pila;
(* Devuelve una pila de Strings (con formato: curso - estudiante) con
las inscripciones de 'i'. Al finalizar, 'i' debe quedar vacío.
La pila debe quedar en orden lexicográfico creciente del código de curso, y
para los cursos en que haya más de un inscripto, en orden cronológico
creciente de inscripción. Es decir, que en el tope de la pila estará el
estudiante que se haya inscripto antes al curso cuyo código sea el menor en
orden lexicográfico.
El tiempo de ejecución debe ser O(n + t.log t), siendo n la cantidad de
inscripciones y t <= T la cantidad de cursos que tienen inscripciones
registradas. *)
Ejemplo (la notación [e1,...,en] representa un pila con los elementos e1, …, en y el elemento e1 en el tope):
Inscripciones en i
CrearInscripciones(i);
InscripcionesCurso(“P2”, [“Sheldon”,“Howard”,“Leonard”], i)
InscripcionesCurso(“P1”,[“Sheldon”], i)
InscripcionesCurso(“P3”,[“Penny”,“Raj”], i)
Pila resultado de InscriptosCursosMayorCodigo de i
[“Penny”,“Raj”]
Pila resultado de ObtenerInscripciones de i
[“P1 – Sheldon”,“P2 – Leonard”,“P2 – Howard”,“P2 – Sheldon”,“P3 – Raj”,“P3 – Penny”]
La cantidad de cursos, T, es una constante accesible. Se dispone de los TADs String y Pila de String, cuyas
operaciones tienen tiempo de ejecución O(1). El TAD String contiene, en particular, la función Concatenar (que
devuelve la concatenación de sus dos parámetros separados por ' - ') y operaciones para comparación lexicográfica.
Para implementar el TAD Inscripciones se pueden utilizar, sin implementar, las operaciones de los TADs vistos en
el curso, indicando cuáles de sus posibles implementaciones (vistas en el curso) se eligen para cumplir con los
órdenes requeridos. Concretamente se pide:
a) Defina el tipo Inscripciones en Modula-2 y describa brevemente la representación utilizada. Explique
brevemente cómo se cumplen: la ordenación en el resultado de ObtenerInscripciones y los tiempos de
ejecución para cada una de las operaciones. Tener en cuenta que no se pide desarrollar el código de las
operaciones del TAD.
b) Asumiendo que hay n inscripciones a q cursos (con n y q números genéricos), ¿cuáles son las entradas con
las que ocurre el mejor caso en ObtenerInscripciones en relación a la cantidad de cursos q? Explique
brevemente.
c) Implemente ObtenerInscripciones. Tenga en cuenta que se pueden utilizar, sin implementar, las
operaciones de los TADs vistos en el curso, especificando sus comportamientos, en lenguaje natural.
Solución
a)
Definición de Inscripciones
TYPE
CeldaCurso = RECORD
codigoCurso: String;
pilaEstudiantes: Pila
END;
RangoInscripciones = [0 .. T];
ColaDePrioridad = RECORD
celdasCursos: ARRAY [1 .. T] OF CeldaCurso;
tope: RangoInscripciones
END;
Inscripciones = ColaDePrioridad;
Representación a utilizar
Es una cola de prioridad implementada con un heap. Los elementos son de tipo registro cuyos campos son el código
del curso y la pila de los inscriptos. La prioridad está determinada por el código del curso. El elemento que tiene la
prioridad es el que corresponde al curso cuyo código es mayor. Además de las operaciones estándar de cola de
prioridad (CrearCP, EsVaciaCP, InsertarCP, MaximoCP y ExtraerMaximoCP) se agrega MaximoCodigoCP que
devuelve (en tiempo O(1)) el código del curso que tiene el máximo código (prioridad).
Cumplimiento de la ordenación de la salida
Mediante MaximoCodigoCP, MaximoPilaCP (MaximoCP) y ExtraerMaximoCP se obtienen las inscripciones en
orden lexicográfico decreciente. Al insertarlas en la pila resultado quedan en orden creciente, dejando en el tope la
que corresponden al curso de menor código. Por otra parte, las inscripciones al mismo curso, como están en orden
cronológico decreciente, y el proceso de desapilar y apilar en la pila resultado invierte el orden, quedan en orden
cronológico creciente.
Cumplimiento de órdenes de ejecución
•
•
CrearInscripciones, EsVacioInscripciones,InscripcionesCurso e InscriptosCursoMayorCodigo son
respectivamente Crear, EsVacia, Insertar y Maximo de Cola de prioridad, que con una implementación de
heap cumple con los órdenes pedidos.
ObtenerInscripciones. Cada inscripción debe ser concatenada con el código del curso y el resultado de esta
concatenación debe ser apilado en la pila resultado. Además la inscripción debe ser desapilada de la pila que
la contenía. Las tres operaciones: apilar, desapilar y concatenar son O(1) por lo que procesar cada inscripción
es O(1). Como hay n inscripciones, el procesamiento de todas ellas es O(n), lo cual justifica el término n en
el orden pedido. Además hay que obtener y extraer las t pilas. Cada pila se obtiene en tiempo O(1) y se
extrae en tiempo O(log t). Por lo tanto el tiempo dedicado a estas operaciones es O(t . log t). Entonces el
tiempo total es O(n + t. log t).
b) El mejor caso se da cuando todas las inscripciones son al mismo curso. ExtraerMaximoCP se ejecuta una sola vez. En
ese caso se cumple t = 1, y por lo tanto el tiempo de ejecución es O(n).
c) PROCEDURE ObtenerInscripciones (VAR i: Inscripciones): Pila;
VAR
res, pilaCurso: Pila;
codigo: String;
BEGIN
res := CrearPila ();
WHILE NOT EsVaciaCP (i) DO
codigo := MaximoCodigoCP (i);
pilaCurso := MaximoPilaCP (i);
WHILE NOT EsVaciaPila (pilaCurso) DO
Apilar (Concatenar (codigo, Tope (pilaCurso)), res);
Desapilar (pilaCurso)
END;
DestruirPila (pilaCurso);
ExtaerMaximoCP (i);
END;
RETURN res
END ObtenerInscripciones;
Nota: en esta solución se usan las primitivas de cola de prioridad EsVaciaCP y
ExtraerMaximoCP. De manera equivalente, como se señaló más arriba, podrían
haberse
usado
las
operaciones
del
propio
TAD
Inscripciones:
EsVacioInscripciones e InscriptosCursoMayorCodigo respectivamente. También se
utilizan las primitivas estándar del TAD Pila.
Descargar