Solución Examen de Programación 2

Anuncio
Instituto de Computación. Facultad de Ingeniería. Universidad de la República
Solución Examen de Programación 2
Diciembre 2005
Ejercicio 2 – Parte a:
Ejercicio 2 – Parte a:
Ejercicio 1:
Solución
PROCEDURE F (L: ListaEnt; K: CARDINAL): ListaEnt;
VAR
result, iter, aux : ListaEnt;
cant, cont : CARDINAL;
BEGIN
cant := 0;
iter := L;
WHILE(iter <> NIL) DO
cant := cant + 1;
iter := iter^.sig
END;
IF (cant > K) THEN
FOR cont := 1 TO (cant-K) DO
L := L^.sig
END
END;
NEW (result); (* celda dummy *)
iter := result;
WHILE(L <> NIL) DO
NEW (aux);
aux^.info := L^.info;
iter^.sig := aux;
iter := aux;
L := L^.sig
END;
iter^.sig := NIL;
aux := result;
result := aux^.sig;
DISPOSE (aux); (* se borra la celda dummy *)
RETURN result;
END F;
Ejercicio 2 – Parte a:
Se plantea una estructura a partir de un campo donde se guarda la información y un arreglo para los sucesores.
Solución
TYPE
ARBOL = POINTER TO NODO_ARBOL;
NODO_ARBOL = RECORD
dato : INTEGER;
hijos : POINTER TO ARRAY [1..N] OF ARBOL
END;
Ejercicio 2 – Parte b:
Se implementa con una función auxiliar recursiva para no tener que chequear condiciones de borde en forma
repetida. La función principal verifica que el árbol no es vacío. La función auxiliar comprueba la condición de
orden parcial tomando como precondición que el árbol no es vacío.
Solución
PROCEDURE ConOrdenParcialRecursivo (a : ARBOL) : BOOLEAN;
VAR
i : CARDINAL;
hayOrden : BOOLEAN;
BEGIN
hayOrden := TRUE;
IF (a^.hijos # NIL) THEN
i := 1;
WHILE (hayOrden AND (i <= N)) DO
IF (a^.hijos^[i] # NIL) THEN
hayOrden := (a^.dato > a^.hijos^[i]^.dato) AND
ConOrdenParcialRecursivo (a^.hijos^[i])
END;
INC (i)
END
END;
RETURN hayOrden
END ConOrdenParcialRecursivo;
(* Solucion de la parte b *)
PROCEDURE ConOrdenParcial (a : ARBOL) : BOOLEAN;
VAR
hayOrden : BOOLEAN;
BEGIN
hayOrden := TRUE;
IF (a # NIL) THEN
hayOrden := ConOrdenParcialRecursivo (a)
END;
RETURN hayOrden
END ConOrdenParcial;
Ejercicio 2 – Parte c:
Se ofrecen dos soluciones: una recursiva y una iterativa. Ambas son válidas pero resulta más clara la primera.
El procedimiento consiste en verificar si el nodo actual no tiene hijos. En ese caso se borra ese nodo y se
termina el proceso. En otro caso, se busca el mayor de sus hijos, se coloca éste en lugar de su padre y se
continúa el proceso a partir de ese hijo.
Solución
(* Solucion recursiva de la parte c *)
PROCEDURE BorrarMaximoRec (VAR a : ARBOL);
VAR
i : CARDINAL;
max, posMax : INTEGER;
BEGIN
IF (a # NIL) THEN
IF (a^.hijos = NIL) THEN
(* Si no tiene hijos se borra el nodo *)
DISPOSE (a);
a := NIL
ELSE
(* En otro caso se busca el mayor *)
max := MIN (INTEGER);
posMax := -1;
FOR i := 1 TO N DO
IF (a^.hijos^[i] # NIL) AND (max <= a^.hijos^[i]^.dato) THEN
max := a^.hijos^[i]^.dato;
posMax := i
END
END;
IF (posMax # -1) THEN
a^.dato := max;
BorrarMaximoRec (a^.hijos^[posMax]);
ELSE
(* El vector de hijos esta vacio *)
DISPOSE (a^.hijos);
DISPOSE (a);
a := NIL
END
END
END
END BorrarMaximoRec;
(* Solucion iterativa de la parte c *)
PROCEDURE BorrarMaximo (VAR a : ARBOL);
VAR
i, cantHijos : CARDINAL;
max, posMax : INTEGER;
iter : ARBOL;
parar : BOOLEAN;
BEGIN
IF (a # NIL) THEN
IF (a^.hijos = NIL) THEN
(* Si no tiene hijos se borra el nodo *)
DISPOSE (a);
a := NIL
ELSE
(* En otro caso se busca el mayor *)
parar := FALSE;
iter := a;
WHILE (NOT parar) DO
cantHijos := 0;
max := MIN (INTEGER);
FOR i := 1 TO N DO
IF (iter^.hijos^[i] # NIL) THEN
IF (max <= iter^.hijos^[i]^.dato) THEN
max := iter^.hijos^[i]^.dato;
posMax := i
END;
INC (cantHijos)
END
END;
iter^.dato := max;
IF (iter^.hijos^[posMax]^.hijos = NIL) THEN
(* El vector de hijos esta vacio, se corta la iteracion *)
parar := TRUE;
DISPOSE (iter^.hijos^[posMax]);
iter^.hijos^[posMax] := NIL;
IF (cantHijos = 1) THEN
(* Era el ultimo hijo, se borra el vector *)
DISPOSE (iter^.hijos);
iter^.hijos := NIL
END
ELSE
(* Se avanza iter *)
iter := iter^.hijos^[posMax]
END
END
END
END
END BorrarMaximo;
Ejercicio 3:
Ejercicio 3 – Parte a:
Solución
DEFINITION MODULE ColaPrio;
TYPE
CPrio;
Rango = [1 .. M];
PROCEDURE empty (VAR C : CPrio);
(*
Retorna la cola vacía *)
PROCEDURE insert (dato : T; ident : Rango; prio : INTEGER; VAR C : CPrio);
(*
Pre : NOT IsFull(C)
Pre : No existe elemento con identificador ident en C
Inserta el dato en la cola C con identificador ident y prioridad prio *)
PROCEDURE IsEmpty (C : CPrio) : BOOLEAN;
(*
Retorna TRUE si C es vacía *)
PROCEDURE IsFull (C : CPrio) : BOOLEAN;
(*
Retorna TRUE si C es llena *)
PROCEDURE max (VAR dato : T; C : CPrio);
(*
Pre : NOT IsEmpty(C)
Retorna en dato el elemento de mayor prioridad
*)
PROCEDURE deleteMax (VAR C : CPrio);
(*
Pre : NOT IsEmpty(C)
Elimina el elemento de mayor prioridad en la cola C *)
PROCEDURE decrPrio (ident : Rango; decr : CARDINAL; VAR C : CPrio);
(*
Decrementa el valor de prioridad del elemento ident en decr unidades
si ident se encuentra en la cola C *)
END ColaPrio.
Ejercicio 3 – Parte b:
Solución
Las restricciones establecidas se pueden satisfacer utilizando un Heap y una Tabla que permita encontrar a
cada elemento del Heap dada su clave.
1
31
2
19
24
3
4
13
21
16
5
6
7=M
Dado que la cantidad máxima de elementos está acotada en M, y que el rango de los identificadores es [1..M],
las estructuras pueden ser:
•
Heap: arreglo con tope (de 1 a M) que almacene elementos de tipo T junto a su prioridad e
identificador.
•
Tabla: arreglo de 1 a M que almacene enteros de rango [0..M] que indican la posición en el Heap del
elemento que tiene como identificador el índice del arreglo (donde 0 podría indicar la no existencia de
dicho elemento).
1
2
3
4
5
6
7
2
1
3
6
4
5
(2,31)
(1,24)
(3,19)
(6,13)
(7,21)
(4,16)
1
2
3
4
5
6
7
tope = 6
La operación max se soluciona obteniendo el primer elemento del Heap, lo cual no requiere recorrer la cola de
prioridad.
La operación isFull se soluciona verificando que el tope del arreglo sea igual a M, lo cual no requiere recorrer
la cola de prioridad.
Para resolver la operación decrPrio, primero se debe obtener la posición en el Heap del elemento al cual se va
a decrementar su prioridad, esto se logra utilizando la Tabla (sin recorrer la cola).
1
2
3
4
5
6
7
2
1
3
6
4
5
(2,31)
(1,14)
(3,19)
(6,13)
(7,21)
(4,16)
1
2
3
4
5
6
7
tope = 6
Luego se realizan los filtrados necesarios en el Heap, lo cual requiere log2(n) comparaciones en el peor caso,
actualizándose a su vez la Tabla. Dado que los elementos se alamacenan en el Heap junto con sus
identificadores, la actualización de la Tabla no requiere recorridas adicionales.
1
2
3
4
2
1
3
6
(2,31)
(1,14)
(3,19)
(6,13)
(7,21)
(4,16)
1
2
3
4
5
6
tope = 6
5
6
7
4
5
7
De esta manera se cumple con la restricción de que la operación decrPrio realice log2(n) comparaciones en el
peor caso, las operaciones insert y deleteMax se resuelven de forma similar.
1
2
3
4
5
1
3
6
(2,31)
(7,21)
(3,19)
(6,13)
(1,14)
(4,16)
1
2
3
4
5
6
tope = 6
TYPE
RangoExt = [0 .. M];
Nodo = RECORD
ident : Rango;
prio : INTEGER;
dato : T;
END;
CPrio = RECORD
map : ARRAY Rango OF RangoExt;
heap : ARRAY Rango OF Nodo;
tope : RangoExt;
END;
5
6
7
4
2
7
Descargar