Estructuras de datos II - Unidad de Programación

Anuncio
Estructuras de datos II.
Convocatoria: Junio 2008
1
Estructuras de datos II
Convocatoria: Junio 2008
Dpto. LSIIS. Unidad de Programación
Normas
Duración: El examen se compone de 1 ejercicio y una colección de preguntas cortas. Su duración será de dos horas
y cuarto. Transcurrida una hora del comienzo del examen se recogerán las preguntas cortas.
Calificaciones: Las calificaciones se publicarán en el tablón de anuncios y en la página web de la asignatura el dı́a
3 de Julio de 2008.
Revisión: La revisión del examen se realizará el dı́a 4 de Julio de 2008.
Soluciones: Las soluciones a los ejercicios se publicarán en el tablón de la asignatura junto con las notas.
1.
Obtención y Filtrado de Claves de una Tabla
[4 puntos]
Se desea añadir una nueva operación al TAD Tabla visto en clase. Dicha operación debe permitirnos
conocer el conjunto de claves que están presentes en la tabla en un momento dado de la ejecución. Además,
la operación mencionada debe ser capaz de filtrar las claves según cierto criterio y obtener unicamente un
subconjunto de ellas. Para ello, la cabecera de la nueva operación será la siguiente:
function F i l t r a C l a v e s
(T : T a b l a ;
F : Tipo Filtro )
return C j t o C l a v e s . C o n j u n t o ;
Dicha operación recibe como segundo parámetro una función booleana que se utiliza para decidir si cada
una de las claves de la tabla debe incluirse o no en el conjunto resultado. La declaración de tipos de dicho
parámetro es la siguiente:
type T i p o F i l t r o i s access function
( C l a v e : in T i p o C l a v e ) return B o o l e a n ;
Finalmente, la operación Filtra Claves devuelve un conjunto de claves en su tercer argumento. Para ello,
se dispone de la siguiente instanciación del TAD genérico de conjuntos:
with C o n j u n t o s ;
package C j t o C l a v e s i s new C o n j u n t o s ( T i p o C l a v e ) ;
Asumimos que tanto la declaración de Tipo Filtro como la instanciación del paquete de conjuntos vienen
dadas en el fichero tablas.ads junto con la cabecera de Filtra Claves.
Se incluye a continuación la parte relevante de interfaz del paquete genérico de conjuntos:
generic
type T i p o E l e m e n t o i s private ;
package C o n j u n t o s i s
type C o n j u n t o i s private ;
function V a c i o return C o n j u n t o ;
function E s V a c i o (C : C o n j u n t o ) return B o o l e a n ;
function P e r t e n e c e (C : C o n j u n t o ; E l t o : T i p o E l e m e n t o ) return B o o l e a n ;
function I n s e r t a r ( E : T i p o E l e m e n t o ; C : C o n j u n t o ) return C o n j u n t o ;
function I n s e r t a r N u e v o ( E : T i p o E l e m e n t o ; C : C o n j u n t o ) return C o n j u n t o ;
function E x t r a e r (C : C o n j u n t o ) return T i p o E l e m e n t o ;
function B o r r a r ( E : T i p o E l e m e n t o ; C : C o n j u n t o ) return C o n j u n t o ;
function C o p i a r ( C1 : C o n j u n t o ) return C o n j u n t o ;
procedure D e s t r u i r (C : in out C o n j u n t o ) ;
end C o n j u n t o s ;
Se recuerda que la operación Insertar Nuevo tiene como precondición que el elemento E a insertar no
pertenece al conjunto C. Esto permite no tener que comprobar dicha pertenencia, de manera que la complejidad de Insertar Nuevo es constante, mientras que la de Insertar es lineal (en la implementación vista
en clase).
La implementación de tablas que tomaremos como punto de partida es la basada en árboles binarios
de búsqueda. Recordamos a continuación las declaraciones de tipos más relevantes en esta implementación:
Estructuras de datos II.
Convocatoria: Junio 2008
2
type Tipo Nodo ;
type T a b l a i s access Tipo Nodo ;
type Tipo Nodo i s
record
Clave : Tipo Clave ;
Info
: Tipo Informacion ;
Izdo
: T a b l a := null ;
Dcho
: T a b l a := null ;
end record ;
Se pide:
Apartado a) (3.0 puntos) Impleméntese la operación Filtra Claves tal y como aparecerı́a en el fichero
tablas.adb. La implementación debe ser obligatoriamente recursiva. Además, obsérvese que la operación Filtra Claves es una función, no un procedimiento.
Apartado b) (0.3 puntos) ¿Habrı́a que modificar algo en la implementación propuesta en el apartado
anterior para que sea válida para el caso de tablas implementadas usando árboles AVL? ¿En tal caso,
qué habrı́a que modificar?
Apartado c) (0.4 puntos) ¿En qué implementación será mas eficiente en tiempo la operación Filtra Claves,
en los árboles binarios de búsqueda o en los AVL? ¿Cuál es el orden de complejidad en el caso de los
árboles de búsqueda? ¿Y en los AVL?
Apartado d) (0.3 puntos) ¿Por qué no es correcto el siguiente código?
with T a b l a s ;
procedure H o r a r i o i s
type T i p o D i a i s
( Lunes , Martes , M i e r c o l e s , J u e v e s , V i e r n e s , Sabado , Domingo ) ;
package T a b l a H o r a r i o i s new T a b l a s (
Tipo Clave
=> T i p o D i a ,
T i p o I n f o r m a c i o n => ( . . . ) ,
”<” => ”<” ) ;
use T a b l a H o r a r i o ;
H o r a r i o : Tabla ;
Dias : C j t o C l a v e s . Conjunto ;
function E s D i a D e D i a r i o
(C : T i p o D i a )
return B o o l e a n
is
begin
return C < Sabado ;
end E s D i a D e D i a r i o ;
begin −− Programa p r i n c i p a l
Crear Vacia ( Horario ) ;
(...)
D i a s := F i l t r a C l a v e s ( H o r a r i o , E s D i a D e D i a r i o ) ;
(...)
Destruir ( Horario ) ;
end H o r a r i o ;
Estructuras de datos II.
Convocatoria: Junio 2008
3
Solución
Apartado a)
procedure Filtro_Auxiliar
(T : Tabla;
F : Tipo_Filtro;
C : in out Cjto_Claves.Conjunto)
is
begin
if T /= null then
if F (T.Clave) then
C := Cjto_Claves.Insertar_Nuevo (T.Clave, C);
end if;
Filtro_Auxiliar(T.Izdo, F, C);
Filtro_Auxiliar(T.Dcho, F, C);
end if;
end Filtro_Auxiliar;
function Filtra_Claves
(T : Tabla;
F : Tipo_Filtro)
return Cjto_Claves.Conjunto is
C: Cjto_Claves.Conjunto := Cjto_Claves.Vacio;
begin
Filtro_Auxiliar( T, F, C );
return C;
end Filtra_Claves;
• La valoración de este apartado es de 3 puntos.
• Filtra Claves es una función. Las soluciones en las que se ha utilizado como si fuese un procedimiento, han obtenido notas que no superan en ningún caso 1.5 puntos (de los 3 puntos que vale
este apartado).
• Las claves de una tabla, no pueden estar repetidas, en caso contrario no habları́amos de una tabla.
Apartado b) No es necesario modificar nada en el código anterior, y servirá igualmente en el caso de
que el árbol fuese AVL. No es necesario consultar la condición de equilibrio de los nodos y tampoco se
ve afectada por la ejecución de la operación de filtrado.
Apartado c) La complejidad es la misma en ambos casos: hay que recorrer todos los elementos de
la tabla y aplicar el filtro a las claves. Dado que hemos utilizado la operación Insertar Nuevo del
paquete Conjuntos, cuya complejidad se asume constante, y considerando que el coste de comprobar la
condición del filtro es constante igualmente, tenemos una complejidad asintótica de O(n), llamando n
al número de elementos almacenados en la tabla. Obsérvese que no es lo mismo el número de elementos
en la tabla que el cardinal de Tipo Clave.
Apartado d) El código a analizar se encuentra completo y correctamente escrito a disposición de los
alumnos como parte del material de la asignatura, más exactamente en el directorio de ejemplos de
aplicación de las implementaciones del TAD Tabla (”horario.adb”). La única diferencia es que se ha
cambiado la llamada al procedimiento Recorrer que aparecı́a en dicho material, por una llamada a la
función Filtra Claves, que es además donde se localiza el error.
En lugar de
D i a s := F i l t r a C l a v e s ( H o r a r i o , E s D i a D e D i a r i o ) ;
deberı́a aparecer
D i a s := F i l t r a C l a v e s ( H o r a r i o , E s D i a D e D i a r i o ’ access ) ;
Convocatoria: Junio 2008
Estructuras de datos II.
2.
4
Preguntas cortas
[6 puntos]
Apellidos: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Nombre: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Número de matrı́cula: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Grupo: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Esta hoja se deberá rellenar con los datos del alumno y entregar como parte del examen.
Este ejercicio se recogerá transcurrida 1 hora desde el comienzo del examen.
1. Dado el grafo dirigido definido por la siguiente lista de adyacencias
( (a , [b,f]) (b , [c,d]) (c , [e]) (d , [c]) (e , []) (f , [e] ) )
Se pide:
(0.3 ptos.) Dibujar el grafo.
Solución: Una posible representación gráfica del grafo es la siguiente:
A
B
C
F
D
E
(0.5 ptos.) Dar la secuencia de nodos resultante de realizar un recorrido en profundidad del grafo
que comience en el nodo a.
Solución: Existen varios recorridos en profundidad del grafo comenzando en el nodo a. Se considera válido cualquiera de los siguientes: a,b,c,e,d,f; a,b,d,c,e,f; a,f,e,b,c,d; a,f,e,b,d,c.
(0.5 ptos.) Idem para un recorrido en anchura, comenzando igualmente en el nodo a .
Solución: Existen también varios recorridos en anchura del grafo comenzando en el nodo a. Se
considera válido cualquiera de los siguientes:
a,b,f,c,d,e; a,b,f,c,e,d; a,b,f,d,c,e; a,b,f,d,e,c; a,b,f,e,c,d; a,b,f,e,d,c; a,f,b,c,d,e; a,f,b,c,e,d; a,f,b,d,c,e;
a,f,b,d,e,c; a,f,b,e,c,d; a,f,b,e,d,c.
2. Considérense árboles multicamino que almacenan números naturales. Se pide:
(0.65 ptos.) Dibujar en la siguiente plantilla - organizada por niveles de profundidad - un árbol
multicamino de grado 4 y profundidad 2 que tenga el mayor número de nodos posible. El alumno
debe escoger los números naturales almacenados en el árbol.
Solución: se muestra una posible solucion. Se pueden por supuesto utilizar otros números naturales, pero es importante que tanto el nodo raı́z como los de nivel de profundidad 1 tengan 3
claves y 4 hijos no vacios.
10 20 30
3 5 8
2
4
7
prof. 0
12 15 18
9
11
14
17
22 26 28
19
21
23
27
35 40 50
29
33
37
44
60
(0.65 ptos.) Dibujar ahora un árbol multicamino de grado 4 y profundidad 2 que tenga el menor
número de nodos posible.
Solución: Como en el caso anterior, se pueden por supuesto utilizar otros números naturales.
Es importante que el nodo raı́z tenga 3 claves, pero solo un hijo no vacio. El nodo del nivel de
profundidad 1 puede tener entre 1 y 3 claves, pero solo debe tener un hijo no vacio.
Estructuras de datos II.
Convocatoria: Junio 2008
5
4 8 12
prof. 0
9
11
Observación importante: como se puede ver, se considera que la profundidad del nodo raı́z es 0. En
ambos apartados, dado que el árbol pedido es de grado 4 , se debe asumir que al menos el nodo raı́z
alcanza dicho grado.
3. ¿Qué dos propiedades debe tener un árbol binario para ser un montı́culo?
(0.4 ptos.) Propiedad 1:
Solución: Propiedad de la forma: todos los niveles del árbol deben estar totalmente ocupados
excepto posiblemente el último nivel, que en caso de tener huecos libres, estos deben estar en la
parte derecha.
(0.4 ptos.) Propiedad 2:
Solución: Propiedad de los valores: el valor almacenado en cualquier nodo del árbol debe ser
mayor que el valor de cualquiera de sus hijos.
4. (0.8 ptos.) Considérese una cola con prioridad implementada con un heap (montı́culo binario almacenado en vector mas contador del número de elementos). En un momento dado, el número de elementos
en la cola es 10. ¿En qué posiciones del vector podrı́a encontrarse el elemento de menor prioridad?
Solución: Asumiendo que no hay valores repetidos en el montı́culo, el elemento de menor prioridad
no puede estar en ningún nodo que tenga algún hijo, porque en tal caso, los hijos tendrán menor valor
que dicho nodo. En un montı́culo con 10 elementos, si tomamos el inicio del array en la posición 1, los
nodos que no tienen hijos (nodos hoja) son los que se encuentran en las posiciones 6, 7, 8, 9 y 10 del
array.
5. Una matriz bidiagonal simétrica es una matriz n × n en la que todos los elementos significativos elementos que pueden tomar un valor distinto de un cierto valor por defecto dado - están situados
en las dos diagonales principales, y tal que al recorrer ambas diagonales en orden creciente de filas,
presentan los mismos elementos.
A continuación mostramos un ejemplo de matriz bidiagonal simétrica de dimensión 6 × 6 que almacena
números naturales y en la que el valor por defecto es el 0:
2
0
0
0
0
2
0
4
0
0
4
0
0
0
7
7
0
0
0
0
1
1
0
0
0
9
0
0
9
0
6
0
0
0
0
6
Se desea implementar estas matrices utilizando un vector V unidimensional, de forma que se minimice el espacio de almacenamiento. Se asume que el primer ı́ndice de posición del vector es
el 1.
Se pide:
(0.2 ptos.) Dibujar el vector V correspondiente a la matriz dada en el ejemplo.
Solución: h2, 4, 7, 1, 9, 6i
(0.4 ptos.) Para una dimensión n cualquiera, ¿cuál es la longitud requerida del vector V ?
Solución: longitud(n) = n
(1.2 ptos.) Escribir el código de la función Posición que asigna a cada elemento de la matriz una
posición en el vector. La cabecera de la función es:
Estructuras de datos II.
Convocatoria: Junio 2008
function Posicion (Fil1
Fil
Col1
Col
return Natural;
:
:
:
:
6
Tipo_Indice_Fila;
Tipo_Indice_Fila;
Tipo_Indice_Columna;
Tipo_Indice_Columna)
Solución: Una posible implementación de dicha función es la siguiente:
function Posicion (Fil1
Fil
Col1
Col
return Natural is
:
:
:
:
Tipo_Indice_Fila;
Tipo_Indice_Fila;
Tipo_Indice_Columna;
Tipo_Indice_Columna)
Pos_f : Natural :=
Tipo_Indice_Fila’Pos (Fil) - Tipo_Indice_Fila’Pos (Fil1);
Pos_c : Natural :=
Tipo_Indice_Columna’Pos (Col) - Tipo_Indice_Columna’Pos (Col1);
begin
if (Pos_f = Pos_c) or else (Pos_f + Pos_c = n - 1) then
return 1 + Pos_f;
else
return 0;
end if;
end Posicion;
En el código se usa n, que es el número de filas (y de columnas) que tiene la matriz.
Obsérvese que el código solución propuesto es aplicable a matrices cuyos ı́ndices puedan empezar
en cualquier valor y no obligatoriamente en un valor predeterminado (el 1 o el 0). Además, la
solución propuesta es aplicable cuando los tipos de los ı́ndices no son numéricos. Por ejemplo,
permite su utilización en matrices cuyos ı́ndices son enumerados.
Una solución menos óptima consistirı́a en definir:
Pos_f : Natural := Fil - Fil1;
Pos_c : Natural := Col - Col1;
y se ha puntuado de forma más baja porque no es aplicable si los ı́ndices son de tipo enumerado.
Descargar