Examen de Programación 2

Anuncio
Instituto de Computación - Facultad de Ingeniería - Universidad de la República
Examen de Programación 2
Diciembre de 2012
Ejercicio 1 ( puntos)
La Administración Nacional de Puertos (ANP) quiere sistematizar la inspección de contenedores en tránsito en el puerto de
Montevideo. El objetivo es optimizar el uso de los recursos de ANP para la inspección de contenedores en búsqueda de
material ilícito, como contrabando y drogas.
De cada contenedor se conocen los siguientes datos:
• Origen (String)
• Destino (String)
• Contenido declarado (String)
• Peso (Real)
• Matrícula del barco (String)
• Ubicación dentro del puerto (String)
El registro de contenedores se hace en base semanal, y a medida que los barcos arriban al puerto se asigna a cada
contenedor descargado un número, que lo identifica. Debido a este sistema de numeración a los contenedores de un mismo
barco se les asignan identificadores consecutivos.
Como la ANP no tiene recursos suficientes para inspeccionar todos los contenedores cada semana se sortea una cantidad I ≤
CR de contenedores para escanear o inspeccionar visualmente, siendo CR la cantidad de contenedores que fue registrada esa
semana. Si al inspeccionar un contenedor se detecta material ilícito se inspeccionan los contenedores consecutivos (anterior
y siguiente) porque es probable que también contengan material ilegal.
Se pide:
1. Especifique en MODULA-2 los TADs Contenedor y ListaContenedores. Este último modela la lista semanal de
contenedores y deberá contar con al menos las siguientes operaciones:
•
•
•
•
Ingresar un nuevo contenedor.
Devolver el contenedor con identificador i, donde 1≤ i ≤ CR
Obtener CR
Vaciar la lista de contenedores
2.
Desarrolle una implementación completa del TAD ListaContenedores que considere las siguientes restricciones:
•
•
•
El ingreso de un nuevo contenedor debe realizarse en O(1)
Obtener CR debe realizarse en O(1)
Asumiendo que estamos accediendo al contenedor con identificador i, donde 1≤ i ≤ CR, se debe poder acceder a
los contenedores anterior y posterior en O(1) en caso de que estos contenedores existan (no existe el contenedor
anterior al que tiene identificador 1 ni el siguiente del que tiene identificador CR).
Se sugiere una implementación basada en listas con posiciones implícitas..
Instituto de Computación - Facultad de Ingeniería - Universidad de la República
Solución
1)
CONST MAX = 50;
TYPE String = ARRAY [1..MAX] OF CHAR;
(* Definición del tipo Contenedor *)
TYPE Contenedor; (* Opaco *)
PROCEDURE CrearContenedor (Peso : REAL; Origen, Destino, ContDecl, MatrBarco,
Ubicacion : String) : Contenedor;
PROCEDURE ObtenerPeso (c : Contenedor) : REAL;
PROCEDURE ObtenerOrigen (c : Contenedor) : String;
PROCEDURE ObtenerDestino (c : Contenedor) : String;
PROCEDURE ObtenerContenidoDeclarado (c : Contenedor) : String;
PROCEDURE ObtenerMatriculaBarco (c : Contenedor) : String;
PROCEDURE ObtenerUbicacion ( c : Contenedor) : String;
PROCEDURE DestruirContenedor (c : Contenedor);
(* ListaContenedor *)
TYPE ListaContenedor; (* Opaco *)
(* POST: Crea la lista vacía y el cursor interno queda indefinido *)
PROCEDURE CrearListaVacia () : ListaContenedor;
(* POST: Ingresa el contenedor 'c' al final de la lista 'l' en O(1) *)
PROCEDURE IngresarContenedor (c : Contenedor; VAR l : ListaContenedor);
(* POST: Devuelve la cantidad de contenedores registrados (CR) en la lista 'l' en O(1) *)
PROCEDURE ObtenerCantContReg (l : ListaContenedor) : CARDINAL;
(* PRE: 1 <= i AND i <= ObtenerCantContReg(l) *)
(* POST: Posiciona el cursor interno de la lista 'l' en el contenedor con identificador 'i' en O(n) en el peor caso *)
PROCEDURE PosicionarCursor (i : CARDINAL; l : ListaContenedor);
(* PRE: ObtenerCantContReg(l) > 0 *)
PROCEDURE ObtenerPosicionCursor (l : ListaContenedor) : CARDINAL;
(* PRE: ObtenerPosicionCursor(l) > 1 *)
(* POST: Devuelve el contendor anterior al de la posición actual del cursor interno de la lista 'l' en O(1) *)
PROCEDURE ContenedorAnterior (l : ListaContenedor) : Contenedor;
(* PRE: ObtenerPosicionCursor(l) < ObtenerCantContReg(l) *)
(* POST: Devuelve el contendor siguiente al de la posición actual del cursor interno de la lista 'l' en O(1) *)
PROCEDURE ContenedorSiguiente (l : ListaContenedor) : Contenedor;
(* PRE: ObtenerCantContReg(l) > 0 *)
(* POST: Devuelve el contendor de la posición actual del cursor interno de la lista 'l' en O(1) *)
PROCEDURE ContenedorActual (l : ListaContenedor) : Contenedor;
(* POST: Libera la memoria de todos los contenedores de la lista 'l' y la deja en el mismo estado como si se invocara
a CrearListaVacia *)
PROCEDURE VaciarLista (l : ListaContenedor);
(* POST: Libera toda la memoria reservada para la lista 'l' y los contenedores *)
PROCEDURE DestruirLista (l : ListaContenedor);
END ListaContenedor.
Instituto de Computación - Facultad de Ingeniería - Universidad de la República
2)
IMPLEMENTATION MODULE ListaContenedor;
FROM Storage IMPORT ALLOCATE, DEALLOCATE;
TYPE
NodoLista = POINTER TO Nodo;
Nodo = RECORD
cont : Contenedor;
pos : CARDINAL;
ant, sig : NodoLista;
END;
ListaContenedor = POINTER TO Lista;
Lista = RECORD
inicio, fin, cursor : NodoLista;
END;
PROCEDURE CrearListaVacia () : ListaContenedor;
VAR l : ListaContenedor;
BEGIN
NEW(l);
NEW(l^.inicio); (* Celda dummy *)
l^.inicio^.ant := NIL;
l^.inicio^.sig := NIL;
l^.inicio^.pos := 0; (* No es tan dummy! *)
l^.cursor := l^.inicio;
l^.fin := l^.inicio;
RETURN l;
END CrearListaVacia;
PROCEDURE IngresarContenedor (c : Contenedor; VAR l : ListaContenedor);
BEGIN
NEW(l^.fin^.sig);
l^.fin^.sig^.ant := l^.fin;
l^.fin := l^.fin^.sig;
l^.fin^.sig := NIL;
l^.fin^.cont := c;
l^.fin^.pos := l^.fin^.ant^.pos + 1; (* Acá sirve inicializar en 0 la posición de la celda dummy *)
END IngresarContenedor;
PROCEDURE ObtenerCantContReg (l : ListaContenedor) : CARDINAL;
BEGIN
RETURN l^.fin^.pos;
END ObtenerCantContReg;
(* PRE: 1 <= i AND i <= ObtenerCantContReg(l) *)
(* POST: Posiciona el cursor interno de la lista 'l' en el contenedor con identificador 'i' en O(n) en el peor caso *)
PROCEDURE PosicionarCursor (i : CARDINAL; l : ListaContenedor);
BEGIN
(* Obtener consecutivos es eficiente! *)
WHILE (l^.cursor^.pos <> i) DO
IF l^.cursor^.pos > i THEN
l^.cursor := l^.cursor^.ant;
ELSE
l^.cursor := l^.cursor^.sig;
Instituto de Computación - Facultad de Ingeniería - Universidad de la República
END;
END;
END PosicionarCursor;
(* PRE: ObtenerCantContReg(l) > 0 *)
PROCEDURE ObtenerPosicionCursor (l : ListaContenedor) : CARDINAL;
BEGIN
RETURN l^.cursor^.pos;
END ObtenerPosicionCursor;
(* PRE: ObtenerPosicionCursor(l) > 1 *)
(* POST: Devuelve el contendor anterior al de la posición actual del cursor interno de la lista 'l' en O(1) *)
PROCEDURE ContenedorAnterior (l : ListaContenedor) : Contenedor;
BEGIN
RETURN l^.cursor^.ant^.cont;
END ContenedorAnterior;
(* PRE: ObtenerPosicionCursor(l) < ObtenerCantContReg(l) *)
(* POST: Devuelve el contendor siguiente al de la posición actual del cursor interno de la lista 'l' en O(1) *)
PROCEDURE ContenedorSiguiente (l : ListaContenedor) : Contenedor;
BEGIN
RETURN l^.cursor^.sig^.cont;
END ContenedorSiguiente;
(* PRE: ObtenerCantContReg(l) > 0 *)
(* POST: Devuelve el contendor de la posición actual del cursor interno de la lista 'l' en O(1) *)
PROCEDURE ContenedorActual (l : ListaContenedor) : Contenedor;
BEGIN
RETURN l^.cursor^.cont;
END ContenedorActual;
(* POST: Libera la memoria de todos los contenedores de la lista 'l' y la deja en el mismo estado como si se invocara
a CrearListaVacia *)
PROCEDURE VaciarLista (l : ListaContenedor);
VAR aBorrar : NodoLista;
BEGIN
l^.cursor := l^.inicio^.sig;
WHILE l^.cursor <> NIL DO
aBorrar := l^.cursor;
l^.cursor := l^.cursor^.sig;
DestruirContenedor(aBorrar^.cont);
DISPOSE(aBorrar);
END;
l^.inicio^.sig := NIL;
l^.fin := l^.inicio;
l^.cursor := l^.inicio;
END VaciarLista;
(* POST: Libera toda la memoria reservada para la lista 'l' y los contenedores *)
PROCEDURE DestruirLista (l : ListaContenedor);
BEGIN
VaciarLista(l);
DISPOSE(l^.inicio); (* La celda dummy *)
DISPOSE(l);
END DestruirLista;
END ListaContenedor.
Instituto de Computación - Facultad de Ingeniería - Universidad de la República
Ejercicio 2 ( puntos)
Sea ABB un tipo que representa árboles binarios de búsqueda cuyos elementos son del tipo TInfo que se describe a
continuación. Los nodos de ABB están ordenados según el campo “clave”.
TInfo = RECORD
clave: CARDINAL;
dato: T;
END;
Se dispone de las siguientes primitivas:
•
PROCEDURE Crear (): ABB;
(* Devuelve un árbol vacío. *)
•
PROCEDURE Cons (info: TInfo; izq, der: ABB): ABB;
(* Crea un árbol con raíz igual a "info" y con subárboles izquierdo y derecho "izq" y "der" respectivamente.
Precondición: info.clave es mayor que las claves en "izq" y menor que las claves en "der". *)
•
PROCEDURE EsVacio (t: ABB): BOOLEAN;
(* Devuelve TRUE si "t" es vacio o FALSE en otro caso. *)
•
PROCEDURE Raiz (t: ABB): TInfo;
(* Devuelve la raíz de "t".
Precondición: NOT EsVacio (t). *)
•
PROCEDURE Izquierdo (t: ABB): ABB;
(* Devuelve el subárbol izquierdo de "t".
Precondición: NOT EsVacio (t). *)
•
PROCEDURE Derecho (t: ABB): ABB;
(* Devuelve el subárbol derecho de "t".
Precondición: NOT EsVacio (t). *)
•
PROCEDURE Mayor (t: ABB): TInfo;
(* Devuelve el elemento de "t" cuya clave es más grande.
Precondición: NOT EsVacio (t). *)
•
PROCEDURE RemoverMayor (VAR t: ABB);
(* Remueve de "t" el nodo cuya clave es más grande y libera los registros de memoria mantenidos por ese nodo.
Precondición: NOT EsVacio (t). *)
•
PROCEDURE Destruir (VAR t: ABB);
(* Libera todos los registros de memoria utilizados para almacenar el árbol "t". El árbol "t" queda indefinido.*)
Se pide:
1. Implemente RemoverMayor accediendo a la representación de ABB. Para ello defina el tipo ABB. La
implementación no debe ser recursiva. No se puede utilizar procedimientos auxiliares ni las primitivas.
2.
Dado un árbol t de tipo ABB, se quiere obtener otro ABB t1 que sólo contenga copias de los nodos de t para los
cuales el campo “dato” es mayor que una cierta cota. El árbol obtenido t1 no debe compartir registros de memoria
con t y debe ser un árbol binario de búsqueda ordenado según “clave”.
Instituto de Computación - Facultad de Ingeniería - Universidad de la República
Para esto se cuenta con la siguiente función auxiliar:
PROCEDURE EsMenor (a,b:T) : BOOLEAN
(* Devuelve TRUE si y sólo si a<b, FALSE en cualquier otro caso .*)
Se debe implementar la función Filtrado, sin definir procedimientos auxiliares ni acceder a la representación
(usando solamente las primitivas y la función EsMenor):
PROCEDURE Filtrado (t: ABB; cota: T): ABB;
(* Devuelve un árbol con los elementos de "t" en los que "dato" es mayor que "cota". *)
A modo de ejemplo, y suponiendo que el tipo T corresponda a strings, en la Figura 1 se presenta un árbol t (sobre a
izquierda) y el resultado de filtrarlo con una cota igual al string “manzana” (sobre la derecha).
3.
Suponga que también se dispone de la siguiente primitiva:
PROCEDURE DestruirRaiz (VAR t: ABB);
(* Libera los registros de memoria mantenidos por la raíz de "t". El árbol "t" queda indefinido.
Precondición: NOT EsVacio (t). *)
Figura 1: Ejemplo del resultado de aplicar la función Filtrado
Usando solo las primitivas, incluida DestruirRaiz , implemente el procedimiento
PROCEDURE Insertar (info: TInfo; VAR t: ABB);
(* Inserta "info" en "t" manteniendo el orden dado por "clave".
Precondición: info.clave no es una clave en "t". *)
4.
Ahora suponga que en cada nodo se mantiene también la altura del árbol. El tipo TInfo pasa a ser el siguiente:
TInfo = RECORD
clave: CARDINAL;
altura: CARDINAL;
dato: T;
END;
Implemente, sin definir procedimientos auxiliares y accediendo directamente a la representación del tipo ABB
definido en la parte 1, RemoverMayorRec (VAR t: ABB), una versión recursiva de RemoverMayor que además
mantenga de manera correcta la altura de cada nodo. La Figura 2 presenta un ejemplo de árbol con el tipo TInfo
modificado para almacenar la altura en cada nodo (izquierda) y el resultado de aplicar la función
RemoverMayorRec sobre dicho árbol (derecha).
Instituto de Computación - Facultad de Ingeniería - Universidad de la República
Figura 2: Ejemplo de aplicación de la función RemoverMayorRec
Solución
1)
TYPE T = CARDINAL;
TInfo = RECORD
clave : CARDINAL;
dato : T;
altura : CARDINAL;
END;
ABB = POINTER TO ABBNodo;
ABBNodo = RECORD;
info : TInfo;
izq, der : ABB;
END;
PROCEDURE RemoverMayor (VAR a : ABB);
(* NOT EsVacio(t)*)
VAR hijo, padre, aBorrar : ABB;
BEGIN
padre := NIL;
hijo := a;
(* Busco el primer nodo que el derecho sea NIL *)
WHILE hijo^.der <> NIL DO
padre := hijo;
hijo := hijo^.der;
END;
aBorrar := hijo;
IF padre = NIL THEN (* Era un arbol sin nodo derecho *)
a := a^.izq;
ELSIF hijo^.izq = NIL THEN (* El más grande es una hoja *)
padre^.der := NIL;
ELSE (* El más grande tiene subarbol izquierdo *)
padre^.der := hijo^.izq;
END;
DISPOSE(aBorrar);
END RemoverMayor;
Instituto de Computación - Facultad de Ingeniería - Universidad de la República
2)
PROCEDURE Filtrado (t : ABB; cota : T) : ABB;
VAR
fizq, fder : ABB;
imayor, iraiz : TInfo;
BEGIN
IF EsVacio(t) THEN
RETURN Crear();
ELSE
fizq := Filtrado(Izquierdo(t), cota);
fder := Filtrado(Derecho(t), cota);
iraiz := Raiz(t);
IF EsMenor(cota, iraiz.dato)THEN
RETURN Cons(iraiz, fizq, fder);
ELSIF EsVacio(fizq) THEN
Destruir(fizq);
RETURN fder;
ELSIF EsVacio(fder) THEN
Destruir(fder);
RETURN fizq;
ELSE (* Ninguno de los 2 es vacío y además la raíz no va *)
imayor := Mayor(fizq);
RemoverMayor(fizq);
RETURN Cons(imayor, fizq, fder);
END;
END;
END Filtrado;
Solución
3)
PROCEDURE Insertar (info : TInfo; VAR t: ABB);
VAR
raiz : TInfo;
izq, der : ABB;
BEGIN
IF EsVacio(t) THEN
t := Cons(info, Crear(), Crear());
ELSE
raiz := Raiz(t);
der := Derecho(t);
izq := Izquierdo(t);
IF raiz.clave < info.clave THEN
Insertar(info, der);
ELSE
Insertar(info, izq);
END;
DestruirRaiz(t);
t := Cons(raiz, izq, der);
END;
END Insertar;
Instituto de Computación - Facultad de Ingeniería - Universidad de la República
4)
PROCEDURE RemoverMayorRec (VAR t : ABB);
VAR borrar : ABB;
BEGIN
(* El arbol no es vacío *)
IF t^.der = NIL THEN
(* Caso base. La raíz es el elemento mayor. *)
borrar := t;
t := t^.izq;
DISPOSE (borrar);
ELSE
(* Caso recursivo. El mayor está en el subárbol derecho. *)
RemoverMayorRec(t^.der);
(* controlar y tal vez modificar altura*)
IF (t^.izq = NIL) OR (t^.info.altura > 1 + t^.izq^.info.altura) THEN
(* La altura de 't' estaba determinada por la de su subárbol derecho, que no era nulo:
t^.info.altura = 1 + hDer, siendo hDer la altura de t^.der antes de la llamada.
Al remover solo un nodo la altura de t^.der quedará igual o disminuirá 1.*)
IF (t^.der = NIL) OR (t^.info.altura = 2 + t^.der^.info.altura ) THEN
(* La altura de t^.der disminuyó 1.*)
t^.info.altura := t^.info.altura - 1;
END;
END;
END;
END RemoverMayorRec;
Descargar