Docsity
Docsity

Prepara tus exámenes
Prepara tus exámenes

Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity


Consigue puntos base para descargar
Consigue puntos base para descargar

Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium


Orientación Universidad
Orientación Universidad


Ingeniería Infórmatica 06 2010, Exámenes de Ingeniería Infórmatica

Examen Recuperación Junio

Tipo: Exámenes

Antes del 2010

Subido el 31/05/2010

tisor-1
tisor-1 🇪🇸

5

(1)

4 documentos

1 / 8

Toggle sidebar

Esta página no es visible en la vista previa

¡No te pierdas las partes importantes!

bg1
Universidad Rey Juan Carlos
Grado en Ingeniería de Computadores
Estructuras de Datos (Curso 1º)
Curso 2009/10
Examen Final Junio
28-6-2010
Normas:
La duración del examen es de 2 horas y 30 minutos.
Cada ejercicio se entregará en hojas separadas.
Ejercicio 1 (Puntuación: 2 puntos)
Sabiendo que la función “Lineal” tiene complejidad O(n) y por tanto un coste c*n, calcular el orden de complejidad en
notación O del procedimiento “Recursivo” que se presenta a continuación:
PROCEDURE Recursivo (VAR A: INTARRAY; inicio, fin: INTEGER);
VAR punto_medio: INTEGER;
BEGIN
IF (inicio < fin) THEN
BEGIN
punto_medio := (inicio + fin) div 2;
Recursivo(A, inicio, punto_medio);
Recursivo(A, punto_medio + 1, fin);
Lineal(A, inicio, punto_medio, fin);
END;
END;
Solución: El procedimiento es recursivo y para obtener la complejidad tenemos que plantear las ecuaciones de recurrencia.
En el caso base (inicio = fin) el problema tiene tamaño 1 mientras que en el caso recursivo, el problema pasa de tener tamaño n
a tener tamaño n/2 en las llamadas recursivas. Esto es así p orque se toma en punto medio y la mitad del problema (inicio hasta
punto_medio) se le pasa a una llamada recursiva y la otra mitad (punto_medio +1 a fin) a otra llamada recursiva. Una vez
retornan las llamadas recursivas hay una llamada de O(n) a “Lineal”.
Por tanto las ecuaciones de recurrencia quedan como sigue:
Expansión de recurrencias
Si n>1:
T(n) = 2T(n/2) + n =
= 2[ 2T(n/4) + n/2] + n = 4T(n/4) + 2n = 2
2
T
A
(n/2
2
) + 2n
= 2
2
[2T(n/8) + n/4] + 2n = 8T(n/8) + 3n =2
3
T
A
(n/2
3
) + 3n
= 2
3
[2T(n/16) + n/8] + 3n = 2
4
T(n/2
4
) + 4n
Es decir la expansión de recurrencias nos deja una fórmula como la que sigue:
La recursión parará cuando n=1, con lo que tendremos
n/2
k
=1 => 2
k
=n => k = log
2
n
Y con ese valor de k podremos resolver la ecuación de recurrencias:
Y por tanto como T
A
(n) Є O(n log(n) ).
T
n
=
{
1, n=1
2T
n/2
+n, n>1
}
T
n
=2
k
T
n
2
k
+kn
T
n
=2
log
2
n
T
1
+n log
2
n=n+n log
n
pf3
pf4
pf5
pf8

Vista previa parcial del texto

¡Descarga Ingeniería Infórmatica 06 2010 y más Exámenes en PDF de Ingeniería Infórmatica solo en Docsity!

Universidad Rey Juan Carlos

Grado en Ingeniería de Computadores

Estructuras de Datos (Curso 1º)

Curso 2009/

Examen Final Junio

Normas:

  • La duración del examen es de 2 horas y 30 minutos.
  • Cada ejercicio se entregará en hojas separadas.

Ejercicio 1 (Puntuación: 2 puntos)

Sabiendo que la función “Lineal” tiene complejidad O(n) y por tanto un coste c*n, calcular el orden de complejidad en

notación O del procedimiento “Recursivo” que se presenta a continuación:

PROCEDURE Recursivo ( VAR A: INTARRAY ; inicio, fin: INTEGER );

VAR punto_medio: INTEGER ;

BEGIN

IF (inicio < fin) THEN

BEGIN

punto_medio := (inicio + fin) div 2;

Recursivo(A, inicio, punto_medio);

Recursivo(A, punto_medio + 1, fin);

Lineal(A, inicio, punto_medio, fin);

END ;

END ;

Solución: El procedimiento es recursivo y para obtener la complejidad tenemos que plantear las ecuaciones de recurrencia.

En el caso base (inicio = fin) el problema tiene tamaño 1 mientras que en el caso recursivo, el problema pasa de tener tamaño n

a tener tamaño n/2 en las llamadas recursivas. Esto es así porque se toma en punto medio y la mitad del problema (inicio hasta

punto_medio) se le pasa a una llamada recursiva y la otra mitad (punto_medio +1 a fin) a otra llamada recursiva. Una vez

retornan las llamadas recursivas hay una llamada de O(n) a “Lineal”.

Por tanto las ecuaciones de recurrencia quedan como sigue:

Expansión de recurrencias

Si n>1:

T(n) = 2T(n/2) + n =

= 2[ 2T(n/4) + n/2] + n = 4T(n/4) + 2n = 2

2

TA(n/

2

) + 2n

2

[2T(n/8) + n/4] + 2n = 8T(n/8) + 3n =

3

TA(n/

3

) + 3n

3

[2T(n/16) + n/8] + 3n = 2

4

T(n/

4

) + 4n

Es decir la expansión de recurrencias nos deja una fórmula como la que sigue:

La recursión parará cuando n=1, con lo que tendremos

n/

k

k

=n => k = log 2 n

Y con ese valor de k podremos resolver la ecuación de recurrencias:

Y por tanto como TA(n) Є O(n log(n) ).

T  n =

1, n= 1

2T  n / 2  +n, n> 1 }

T  n = 2 k T

n

2

k  +kn

T  n = 2

log 2 n

T  1  +n log 2 n=n+n log  n 

Ejercicio 2 (Puntuación: 2 puntos)

Usando el TAD TipoABinBusq (árbol binario de búsqueda) siendo el tipo de sus elementos el tipo INTEGER, escriba un

subprograma que reciba un árbol binario de búsqueda y dos enteros n y m (siendo n < m ), y escriba en pantalla todos los

números x contenidos en dicho árbol que cumplan: n ≤ x ≤ m. Las operaciones del interfaz de la unidad del TAD son las

siguientes:

PROCEDURE CrearABinBusqVacio ( VAR arbol: TipoABinBusq); (* POST: Construye un arbol binario de búsqueda sin elementos *)

PROCEDURE ConstruirABinBusq (ai: TipoABinBusq; r: TipoElemento; ad: TipoABinBusq; VAR arbol: TipoABinBusq); (PRE: NO EsABinBusqVacio (ai) Y NO EsABinBusqVacio(ad) Y Maximo(ai)<e<Minimo(ad))) (*POST: Construye árbol bin. de búsq. a partir de izdo y dcho y de un nodo raiz *)

FUNCTION Raiz (arbol: TipoABinBusq): TipoElemento; (* PRE: NOT EsArbolBinVacio (arbol) ) ( POST: Nodo raiz de arbol *)

FUNCTION HijoIzq (arbol: TipoABinBusq): TipoABinBusq; (* PRE: NOT EsArbolBinVacio (arbol) ) ( POST: Subárbol hijo izquierdo de arbol ) FUNCTION HijoDer (arbol: TipoABinBusq) : TipoABinBusq; ( PRE: NOT EsArbolBinVacio (arbol) ) ( POST: Subárbol hijo derecho de arbol *)

FUNCTION EsABinBusqVacio (arbol: TipoABinBusq): BOOLEAN ; (* POST: Devuelve TRUE si arbol no tiene elementos y FALSE si los tiene. *)

PROCEDURE Insertar (e: TipoElemento; VAR arbol: TipoABinBusq); (* POST: Devuelve un árbol binario de búsqueda que contiene los elementos originales más un nuevo nodo: el que corresponde al elemento e*)

PROCEDURE Eliminar(e: TipoElemento; VAR arbol: TipoABinBusq); (* POST: Devuelve el árbol binario de búsqueda con los mismos elementos excepto el elemento e, cuyo nodo es eliminado *)

FUNCTION Pertenece (e: TipoElemento; arbol: TipoABinBusq): BOOLEAN ; (* POST: Devuelve TRUE si e está en el árbol y FALSE en caso contrario *)

FUNCTION Maximo(arbol: TipoABinBusq): TipoElemento; (PRE: NOT EsABinBusqVacio(arbol))

FUNCTION Minimo(arbol: TipoABinBusq): TipoElemento; (PRE: NOT EsABinBusqVacio(arbol))

FUNCTION Buscar(e: TipoElemento; arbol: TipoABinBusq): TipoABinBusq; (* POST: Devuelve el subárbol cuya raíz es el nodo buscado si se encuentra, y NIL si no se encuentra*)

Solución

Una posible solución consiste en recorrer el árbol binario de búsqueda en in-orden y comenzar a escribir una vez hemos

encontrado el valor n y hasta que encontremos el valor m en la raíz de un subárbol. El procedimiento que nos piden puede

quedar como sigue:

PROCEDURE EscribirRango(arbol: TipoABinBusq; n, m: Integer);

BEGIN

IF EsABinBusqVacio(arbol) THEN

Writeln('El árbol está Vacío')

ELSE IF (n>m) THEN

Writeln('n es mayor que m')

ELSE

{ Hacemos una llamada a un procedimiento recursivo recorrerá el árbol de binario de búsqueda en in-orden y una vez

encuentre un elemento >=n, comenzará a escribir todos los elementos hasta que encuentre un elemento >= m }

EscribirRangoAux(arbol, n, m);

END;

Ejercicio 3 (Puntuación: 3 puntos)

A continuación se presenta la especificación algebraica de ciertas operaciones sobre listas:

OPERACIONES

Misterio1: TipoLista -> TipoLista

Misterio2: TipoLista x TipoLista -> Booleano

Misterio3: TipoLista x TipoLista -> Booleano

ECUACIONES

Misterio1(CrearVacia) = CrearVacia

Misterio1(Construir(e,lista)) = InsertarFinal(e, Misterio1(lista))

Misterio2(CrearVacia,lista) = CIERTO

Misterio2(Construir(e,lista),CrearVacia) = FALSO

Misterio2(Construir(e1,l1),Construir(e2,l2)) = (e1 = e2) Y Misterio2(l1,l2)

Misterio3(lista,CrearVacia) = EsVacia(lista)

Misterio3(l1,Construir(elem,l2) = Misterio2(l1,Construir(elem,l2)) O Misterio3(l1,l2)

Se pide:

a) Explicar razonadamente, y utilizando ejemplos, qué hace cada una de las operaciones Misterio1, Misterio2, Misterio3.

b) Implementar iterativamente (sin utilizar recursividad) la operación Misterio2, teniendo en cuenta la siguiente declaración

de TipoLista:

TipoLista = ^TipoNodo;

TipoNodo = RECORD

elemento: TipoElemento;

siguiente: TipoLista;

END;

Solución:

a) Explicar razonadamente, y utilizando ejemplos, qué hace cada una de las operaciones Misterio1, Misterio2, Misterio3.

  • Primero intentaremos establecer qué hace la operación Misterio1 con un ejemplo:

Le pasamos la lista [1,2,3]:

Misterio1(Construir(1, Construir(2, Construir(3, CrearVacia)))) =

InsertarFinal(1, Misterio1(Construir(2, Construir(3, CrearVacia)))) =

InsertarFinal(1, InsertarFinal(2, Misterio1(Construir(3, CrearVacia)))) =

InsertarFinal(1, InsertarFinal(2, InsertarFinal(3, Misterio1(CrearVacia)))) =

InsertarFinal(1, InsertarFinal(2, InsertarFinal(3, CrearVacia)))

InsertarFinal lo que hace es colocar el elemento al final de la lista, así que:

InsertarFinal(1, InsertarFinal(2, InsertarFinal(3, CrearVacia))) =

InsertarFinal(1, InsertarFinal(2, Construir(3, CrearVacia))) =

InsertarFinal(1, Construir(3, Construir(2, CrearVacia))) =

Construir(3, Construir(2, Construir(1, CrearVacia))) =

Por tanto :

Misterio1(Construir(1, Construir(2, Construir(3, CrearVacia)))) = Construir(3, Construir(2, Construir(1, CrearVacia)))

O lo que es lo mismo, Misterio1 da la vuelta a la lista original. Por tanto, la operación podría llamarse Invertir.

  • Después intentaremos establecer qué hace la operación Misterio2 con un ejemplo:

Si hacemos la llamada a Misterio2 con las listas [1, 2] y [1, 2, 3] tendremos,

Misterio2(Construir(1, Construir(2, CrearVacia)), Construir(1, Construir(2, Construir(3, CrearVacia)))) =

(1=1) Y Misterio2(Construir(2, CrearVacia), Construir(2, Construir(3, CrearVacia))) =

(1=1) Y (2=2) Y Misterio2(CrearVacia, Construir(3, CrearVacia)) =

(1=1) Y (2=2) Y CIERTO = CIERTO

¿Qué ocurre si damos la vuelta a los argumentos anteriores y hacemos la llamada con [1, 2, 3] y [1, 2]?

Misterio2(Construir(1, Construir(2, Construir(3, CrearVacia))), Construir(1, Construir(2, CrearVacia))) =

(1=1) Y Misterio2(Construir(2, Construir(3, CrearVacia)), Construir(2, CrearVacia)) =

(1=1) Y (2=2) Y Misterio2(Construir(3, CrearVacia)), CrearVacia) =

(1=1) Y (2=2) Y FALSO = FALSO

Por tanto la operación Misterio2 nos dice si la lista que aparece como primer argumento es un prefijo de la lista que aparece en

segundo lugar. Lo que es lo mismo, la lista que aparece en segundo lugar es igual a la lista que aparece en primer lugar

concatenada con algo más. Así que la operación Misterio2 podría llamarse EsPrefijo.

  • Por último vamos a establecer qué hace la operación Misterio3:

Observando las ecuaciones de esta operación en el caso recursivo:

Misterio3(l1,Construir(elem,l2) = Misterio2(l1,Construir(elem,l2)) O Misterio3(l1,l2)

Vemos que la lista l1, nunca cambia en las llamadas recursivas a Misterio3 o Misterio2. Esto es l1 es siempre l1 y no se le

quitan elementos. Por otro lado podemos reescribir la ecuación con lo que sabemos de Misterio2:

Misterio3(l1,Construir(elem,l2) = Esprefijo(l1,Construir(elem,l2)) O Misterio3(l1,l2)

Por tanto Misterio3 es cierto si l1 es prefijo de la lista que se pasa como segundo parámetro a Misterio3. Además se hace una

llamada recursiva a Misterio3 con el resto, l2, de la segunda lista. Por tanto Misterio3 comprueba, para cada elemento de la

segunda lista, si la lista l1 es prefijo. O lo que es lo mismo Misterio3 comprueba si l1 es una sublista de la segunda lista. La

operación Misterio3 podría llamarse EsSublista.

b) Implementar iterativamente (sin utilizar recursividad) la operación Misterio2, teniendo en cuenta la siguiente declaración

de TipoLista:

TipoLista = ^TipoNodo;

TipoNodo = RECORD

elemento: TipoElemento;

siguiente: TipoLista;

END;

Ahora ya sabemos que Misterio2 es la operación EsPrefijo:

FUNCTION EsPrefijo(l1, l2: TipoLista): Boolean ; VAR aux1, aux2: TipoLista; iguales: Boolean ;

BEGIN

IF l1 = NIL THEN EsPrefijo := TRUE ELSE IF l2 = NIL THEN EsPrefijo := FALSE { Si l1 no es la lista vacía y l2 es vacía, entonces l1 no es prefijo} ELSE BEGIN aux1 := l1; aux2 := l2; iguales := TRUE; { l1 y l2 son <> NIL cuando llegamos aquí por las condiciones anteriores } WHILE (aux2 <> NIL) AND (aux1 <> NIL) AND iguales DO BEGIN iguales := (aux1^.elemento = aux2^.elemento); aux2 := aux2^.siguiente; aux1 := aux1^.siguiente; END { Es prefijo si se acabó la lista 1 y todos los elementos eran iguales hasta ese punto} EsPrefijo := iguales AND (aux1 = NIL); END ; END ;

PROCEDURE CrearColaVacia ( VAR cola: TipoCola);

BEGIN

cola.principio := 0;

cola.final := MAX_ELEM-1; { De esta forma cuando insertemos el primer elemento cola.final = 0 }

cola.longitud := 0;

END;

PROCEDURE Insertar (elemento: TipoElemento; VAR cola: TipoCola);

(* PRE: "La cola no está llena" ) ( POST: "Construye una cola, con elemento como ultimo" *)

BEGIN

{ Nota: esta implementación no hace nada cuando la cola está llena. Sería muy interesante añadir una operación EstaLlena

para poder detectar esa situación }

IF cola.longitud < MAX_ELEM THEN

BEGIN

cola.final := SiguientePosicionCircular(cola.final, MAX_ELEM);

cola.vector(cola.final) := elemento;

cola.longitud := cola.longitud + 1;

END;

END;

FUNCTION EsColaVacia (cola: TipoCola): BOOLEAN ;

(* POST: resultado = "Decide si una cola es o no vacia" *)

BEGIN

EsColaVacia := (cola.longitud = 0);

END;

FUNCTION IgualCola (cola, cola2: TipoCola): BOOLEAN ;

(* POST: resultado = (cola.cola = cola2.cola) *)

VAR

aux: INTEGER;

BEGIN

IF cola.longitud <> cola2.longitud THEN

IgualCola := FALSE

ELSE IF cola.longitud = 0 THEN { Si las dos colas están vacías entonces son iguales }

IgualCola := TRUE

ELSE { Las colas tienen la misma longitud y es >0 }

BEGIN

IgualCola := TRUE;

aux := cola.principio;

aux2 := cola2.principio;

WHILE IgualCola AND (aux <> cola.final) DO {las dos colas tienen igual longitud, no hace falta preguntar por aux2}

BEGIN

IgualCola := cola.vector(aux) = cola2.vector(aux2);

aux := SiguienteCircular(aux, MAX_ELEM);

aux2 := SiguienteCircular(aux2, MAX_ELEM);

END;

{ Cuando salimos del bucle o bien IgualCola = FALSE o bien aux = cola.final, por tanto hace falta comprobar la

última posición }

IgualCola := IgualCola AND (cola.vector(aux) = cola2.vector(aux2));

END;

FUNCTION PrimeroCola (cola: TipoCola): TipoElemento;

(* PRE: NOT EsColaVacia(cola) ) ( POST: resultado = "Primer elemento de una cola *)

BEGIN

PrimeroCola := cola.vector(cola.primero);

END;

PROCEDURE Eliminar ( VAR cola: TipoCola);

(* PRE: NOT EsColaVacia(cola)) ( POST: "Devuelve la cola resultante de eliminar su primer elemento *)

BEGIN

IF cola.longitud > 0 THEN

BEGIN

cola.inicial := SiguientePosicionCircular(cola.inicial, MAX_ELEM);

cola.longitud := cola.longitud -1;

END

END;

PROCEDURE CopiarCola (cola: TipoCola; VAR cola2: TipoCola);

(* POST: "Copia de cola en la estructura de cola2" *)

BEGIN

cola2.final := cola.final;

cola2.inicial := cola.inicial;

cola2.longitud := cola.longitud;

cola2.vector := cola.vector;

END;