Está en la página 1de 9

Algoritmos y Estructuras de Datos I Departamento de Computacin Facultad de Ciencias Exactas y naturales Universidad de Buenos Aires

Ejercicios de entrenamiento para el coloquio/final de Algoritmos I Segundo Cuatrimestre 2013 Ejercicio 1 Indicar verdadero o falso: 1.Si un programa es correcto respecto de una especificacin entonces pasa exitosamente todos los casos de testeo para valores que satisfacen la precondicin. 2.Si dos programas que reciben un argumento de entrada, ambos satisfacen la misma especificacin, entonces para cada posible valor de entrada ambos programas dan el mismo valor. Respuesta 1. Verdadero. Los casos de testeo son un subconjunto de los casos contemplados en la especificacin. 2. Falso. Por ejemplo, si la postcondicin de la especificacin es True, existen dos valores diferentes que cumplan dicha postcondicin. Ejercicio 2 Sea (P,Q) la especificacin de un problema, donde P es la precondicin y Q es la postcondicin. Sea un programa foo correcto respecto de (P, Q). Indicar verdadero o falso y justificar: 1. foo es correcto respecto de (P v R, Q) 2. foo es correcto respecto de (P, Q ^ S) 3. foo es correcto respecto de (P, Q v S) 4. foo es correcto respecto de (P, P) 5. foo es correcto respecto de (Q,P) 6. foo es correcto respecto de (Q,Q) Respuesta 1. Falso. Si tomamos P == False, Q == False y R == True, todo programa cumple con la especificacin (P, Q) pero ninguno con (P v R, Q). 2. Falso. Si tomamos P == True, Q == True y S == False, todo programa cumple con (P, Q) pero ninguno con (P, Q ^ S). Ejercicio 3 Qu es un tipo de datos? Dar un ejemplo de un tipo de datos abstracto y uno de un tipo de datos algebraico. Respuesta Un tipo de datos es un conjunto de valores con operaciones asociadas, y tiene un nombre. Un ejemplo de tipo abstracto de datos abstracto es un grafo, que consiste en un conjunto finito de vrtices y un conjunto de aristas, que son pares de vrtices Hay un observador de la cantidad de vrtices, uno de la cantidad de aristas, y un observador que indica si hay o no una arista entre dos vrtices: Invariantes de tipo, cantidad de vrtices mayor que 0, cantidad de ejes entre 0 y cantidad de vrtices al cuatrado. Un ejemplo de un tipo algebraico de datos algebraico es una tupla de nmeros enteros. Ejercicio 4 a. Proponer un conjunto de valores y dar un ejemplo de un tipo algebraico de datos que sea adecuado para representarlo. b. Dar otro ejemplo de tipo algebraico de datos que sea inadecuado para representar al mismo conjunto de valores. En ambos casos justificar. Respuesta no incluida

1/9

Ejercicio 5 Indicar las similitudes y diferencias del tipo de datos lista y del tipo de datos arreglo vistos como tipos abstractos de datos (primitivos). Dar sus observadores y sus invariantes de tipos. Respuesta Similitudes: - Ambos tipos de datos permiten representar colecciones ordenadas de cualquier cantidad de elementos incluyendo la coleccin vaca. - Todos los elementos del arreglo, tanto como todos los de la lista, deben ser del mismo tipo. Diferencias: - El acceso de un elemento del arreglo es directo, en cambio el acceso a un elemento de una lista es secuencial (es necesario acceder a sus elementos previos) siendo esto menos eficiente. - En los arreglos hay que guardar su tamao por separado (en otra variable) pues la estructura no lo almacena, mientras que esto no ocurre con las listas. - En la lista existe la posibilidad de variar la longitud de la misma agregando o eliminando elementos (aunque al ser utilizadas en Haskell, por la transparencia referencial, al agregar o eliminar elementos sta no se modifica sino que se genera una nueva lista con los cambios); mientras que en el arreglo la longitud debe ser prefijada. (Extiendo el lenguaje de especificacin para poder incluir en el arreglo otro parmetro de tipo, siendo ste el tamao del arreglo pues debe ser prefijado, y tomo el conjunto Nat como el de los naturales, pues no puede ser instanciado con un tamao negativo.) tipo Arreglo<T, Nat> { observador iesimo(a: Arreglo<T, n: Nat>, i: Int) : <T>{ requiere 0 <= i < n; } } tipo Lista<T> { observador long(l: Lista<T>): Int; observador cabeza(l: Lista<T>) : <T>{ requiere long(l)>0; } observador cola(l: Lista<T>) : Lista <T>{ requiere long(l)>0; } invariante long(l:Lista<T>) >=0; } Ejercicio 6 Dar un ejemplo de un programa imperativo donde no se viole la transparencia referencial. Justificar. Respuesta int main() { int x=0; return x; } Justificacin: Hay una nica asignacin para la variable x. Ejercicio 7 Definir en Haskell un tipo de datos que represente un rbol binario de nmeros enteros, que tenga un nmero entero en cada nodo y en cada hoja. Dar la funcin en Haskell que recorre un rbol de stos en inorden, y produce la lista de los nodos visitados.

2/9

Respuesta del ejercicio 7 data Arbol = Hoja Int | Nodo Int Arbol Arbol inOrden :: Arbol -> [Int] inOrden (Hoja x) = [x] inOrden (Nodo x i d) = (inOrden i) ++ [x] ++ (inOrden d) Ejercicio 8 El algoritmo de la bsqueda binaria se puede extender al de bsqueda ternaria, donde en cada iteracin el arreglo se divide en tres partes y se selecciona el tercio de bsqueda apropiado. Especificar el problema de bsqueda ternaria y programarlo en lenguaje imperativo. Dar el invariante del ciclo. Respuesta Tomo T como un tipo de datos que admite orden. problema buscarTern(l: [T], n: Z, x: T) = res : Z { requiere n == |l|; requiere (paraTodo i <-- [0..|l|-1)) l[i] < l[i+1]; asegura res == (x <-- l); } A modo de implementar el algoritmo en C, tomo T como int (entero), pero se podra tomar cualquier otro tipo de datos que admita orden. bool buscarTern(int a[], int n, int x) { int i = 0, d = n - 1; bool res; int m1, m2; if (x < a[i] || x > a[d]) res = false; else { while (d >= i + 3) { m1 = i + (d - i) / 3; m2 = i + (d - i) * 2 / 3; if (x == a[m1]) i = d = m1; else if (x == a[m2]) i = d = m2; else if (x < a[m1]) d = m1; else if (x < a[m2]) { i = m1; d = m2; } else i = m2; } res = (a[i] == x || a[d] == x || a[i+d/2]==x); } return res; } El smbolo / indica divisin entera. El invariante del ciclo es: // invariante I: 0 <= i <= d < n && a[i] <= x <= a[d]; Ejercicio 9 1.Enunciar el teorema del invariante. 2.Dar un ejemplo que cumple las hiptesis y otro ejemplo que no. 3.Enunciar el teorema del invariante con la siguiente modificacin: consignar que la funcin variante sea creciente en cada iteracin del ciclo.

3/9

Respuesta del ejercicio 9 Teorema del invariante: Para que un ciclo de la forma: // vale Pc while (B) { // invariante I // variante v; cota c // estado E1 /* cuerpo */ // estado E2 } // vale Qc sea correcto debe cumplir las siguientes 5 condiciones: 1. La precondicin implica el invariante: Pc -> I 2. La postcondicin vale al final: I ^ B -> Qc 3. El cuerpo del ciclo preserva el invariante: /*B ^ I*/, {cuerpo} -> I 4. La expresin variante es estrictamente decreciente en la ejecucin del ciclo: v@E1 > v@E2 5. Si la expresin variante pasa la cota el ciclo termina: I ^ v <= c -> B 1) Ejemplo en donde se cumple: int i = 0; // vale Pc: i == 0 while (i < 10) { // invariante I: 0 <= i <= 10 // variante v: 10 i; cota c: 0 i++; } // vale Qc: i == 10 2) Para construir un ejemplo en donde NO se cumpla, basta con reemplazar Qc por i == 11; 3) Mismo enunciado, excepo puntos 4. y 5 que se reemplazan por 4. La expresin variante es estrictamente creciente en la ejecucin del ciclo: v@E1 < v@E2 5. Si la expresin variante pasa la cota el ciclo termina: I ^ v >= c -> B. Ejercicio 10 Sea C un predicado con la siguiente propiedad: hay un primer nmero natural n0 > 1 que cumple C y todos los naturales mayores que n0 tambin cumplen C. Dar un algoritmo que resuelva el problema de encontrar n0 y que sea ms rpido que el de la simple bsqueda lineal. El algoritmo debe aprovechar la propiedad de la condicin C, y en vez de visitar los naturales secuencialmente, visita solamente algunos, dando saltos exponencialmente grandes. Respuesta int rapitdito { int j=0; while (! C(2^j)) j++; int i = 2^{j-1}, d = 2^j; while ( d>= i+2) { int m = (i + d) / 2; if (!C(m) && C(m+1) ) { i = m; d=m+1; } else if (!C(m) && !C(m+1)) { i = m; } else { d = m; } // caso C(m) es verdadero } return d; }

4/9

Ejercicio 11 Dar una funcin en Haskell que resuelva el siguiente problema. problema lcp(a: [[Char]])= res: [Z]{ requiere long(a)>= 1 asegura res=[longitud_prefijo_comun(a[i],a[i+1]) | i<- [0..long(a)-2]] aux longitud_prefijo_comun(s, t)= max[i +1 | i<- [0.. min[long(s), long(t)]], s[0..i]== t[0..i] ] } donde max y min son las funciones que seleccionan, respectivamente, los valores mximos y mnimos de una lista de enteros. Respuesta Faltara agregar que max de una lista vaca es 0 para que no se indefina la especificacin en caso de no existir un prefijo en comn. Habiendo agregado eso, la funcin en Haskell sera: longPrefComun :: [Char] -> [Char] -> Int [] _ = 0 _ [] = 0 (x:xs) (y:ys) | x == y = 1 + (longPrefComun xs ys) | otherwise = 0 lpc :: [[Char]] -> [Int] lpc [_] = [] lpc (x:(y:xs)) = (longPrefComun x y) : (lpc xs) Ejercicio 12 Dar la postcondicin Q para la cual la siguiente funcin f es correcta. problema f(n:Z) = res:[[Char]] { requiere n >= 0; asegura Q: ...; } f :: Int -> [[Char]] f 0 = [] f 1 = [0, 1] f n | n > 0 = h '0' (f (n - 1)) ++ h '1' (f (n - 1)) h :: Char -> [[Char]] -> [[Char]] h x [] = [] h x (y : ys) = (x : y) : h x ys Respuesta Si bien la postcondicin Q == True hace que la funcin f (como cualquier otra funcin) sea correcta, el comportamiento de la misma est determinado por la postcondicin: asegura Q: res == [bin(x, n) | x <-- [0..2^n)]; aux bin(x: Z, n: Z) : [Char] = [if (x / (2^(n-i-1))) mod 2 == 0 then 0 else 1 | i <-- [0..n)]; Ejercicio 13 Dado el siguiente problema: problema bblog(x:Z)= res:Z{ requiere x>=1 asegura res=[log2 x] } donde [ ] denota la parte entera, y log2 denota el logaritmo en base 2.

5/9

1.Cmo usaras el algoritmo de bsqueda binaria para resolver el problema bblog? Describir (dar el pseudocdigo) la funcin para ser programada en imperativo y codificarla. 2.Dar la especificacin del ciclo utilizado (Precondicin y Postcondicin del ciclo, Invariante, guarda, funcin variante y cota). 3.Programar la funcin en Haskell. Respuesta no incluida. Queda como ejercicio Ejercicio 14 Qu es una variable en lenguaje imperativo? Explicar la operacin de asignacin, y dar su semntica usando la nocin de estado, y transformacin de estados. Cmo difieren las variables en imperativo de las variables en funcional? Respuesta no incluida. Ejercicio 15 Dado un programa imperativo Cada vez que se ejecuta con los mismos argumentos de entrada, realiza la misma transformacin de estados? Respuesta S Ejercicio 16 El paradigma de programacin imperativa permite pasar argumentos por copia y por referencia. Dar dos razones por las cuales al programar una funcin conviene elegir el pasaje por referencia. Respuesta Conviene elegir el pasaje por referencia: - Si se desea que una funcin modifique el valor de una o ms variables pasadas como parmetro. -Si se desea pasar como parmetro un objeto de gran tamao a una funcin se ahorra tiempo si este objeto se pasa por referencia en vez de por copia. Esto es porque para el pasaje de parmetros por referencia basta con copiar en el stack del programa la direccin de memoria en la que se encuentra el objeto, mientras que para el pasaje de parmetros por copia, debe copiarse el objeto entero, que asumimos que ocupa ms que su direccin de memoria. Ejercicio 17 Dar tres razones por las cuales una funcin recursiva se puede indefinir. Respuesta Tres posibles razones: - No hay un caso base, o bien ste nunca se ejecuta (y se genera una cantidad infinita de reducciones). - Se llama a la funcin con parmetros sobre los que la funcin no est definida (no hay ecuaciones suficientes). - Se ejecuta alguna operacin invlida como divisin por cero. Ejercicio 18 A qu se llama rdenes de evaluacin en el paradigma de la programacin funcional? Describir ventajas y desventajas de cada uno. Respuesta En el paradigma de la programacin funcional se llama rdenes de evaluacin a las diferentes tcnicas que existen para realizar las reducciones. En la clase terica vimos dos tipos de rdenes de evaluacin: el aplicativo y el normal: el aplicativo consiste en comenzar por reducir los argumentos del patrn, para una vez llevado stos a sus formas normales, seguir por la reduccin de las expresiones del lado derecho; el rden de evaluacin normal en cambio, consiste en reducir primero las expresiones del lado derecho slo hasta obtener los argumentos necesarios del patrn en la forma normal. En la mayora de los casos, el orden de evaluacin normal es el ms eficiente pues si existe una forma normal de la expresin, con este algoritmo se obtiene dicha confluencia de forma segura (no se indefine), mientras que con el rden de evaluacin aplicativo esto no siempre ocurre y se puede caer en una cadena de reducciones infinitas.

6/9

Adems, la eficiencia del orden normal por sobre el orden aplicativo tambin se ve reflejada cuando ambos pueden obtener la confluencia, en la cantidad de pasos para reducir una expresin, excepto en casos como: func x = x + x + ... + x + x (n veces) >>> func (fibo 20) pues en este ejemplo el orden normal realizar n reducciones de (fibo 20) mientras que el orden aplicativo realizar slo una reduccin del lado izquierdo para luego aplicar el valor final de x a sus 20 asignaciones del lado derecho. Por este motivo, Haskell (en particular) adems de utilizar el orden normal, utiliza la transparencia referencial del paradigma funcional para agregar memorizacin de expresiones, llamndose este algoritmo (orden de evaluacin normal con memorizacin) lazy, dejando atrs cualquier ventaja del orden de evaluacin aplicativo. Ejercicio 19 Sea el siguiente programa en C++. int p(){ int x=2; while (x>=0){ if (x mod 2==0) else } return x; } 1.Sea la siguiente expresin variante v=1/(2x), si x es par; v=1/x si x es impar Por qu no sirve para demostrar terminacin? 2.Este programa termina? 3. Respuesta a) Porque fv debe ser una expresin entera. b) El programa no termina pues x nunca se hace negativo. Sea B: x >= 0. Si al iniciar una iteracin x es par, entonces x se incrementar por lo que al finalizar la iteracin seguir valiendo la guarda B: x >= 0; Si al iniciar una iteracin x es impar, entonces x >= 1 (por ser x >= 0 y ser x impar). Luego de la instruccin x = x 1; vale x >= 0. Por lo tanto al finalizar la iteracin seguir valiendo B: x >= 0 Como la precondicin del ciclo implica B (pues x == 2 --> x >= 0), es decir, la ejecucin entra en el ciclo, y como ya vimos, el cuerpo del ciclo preserva B. Conclumos que el programa no termina. Ejercicio 20 data A4 a = Hoja a | Nodo data A2 a = Hoja a | Nodo A4 a A4 a A4 a A4 a A2 a A2 a x= 2x+1; x=x-1;

problema de4a2(x: A4 a) = y: A2 a requiere completo(x) asegura altura(y) <= 2 altura(x) asegura preorden(x)==preorden(y) Asumir que las expresiones auxiliares completo(x) afirma si el rbol x tiene todas sus hojas a la misma altura. altura(x) es la altura del rbol x preorden(x) es la lista de los elementos del arbol x recorridos en prerden. a. Dar el algoritmo que resuelve este problema y programarlo en Haskell. b. Dar la expresin variante de cada una de las funciones utilizadas. Respuesta no incluida.

7/9

Ejercicio 21 problema f(a:[Z], b:[Z]) modifica b asegura paratodo i->[0..n-1) a[[b[i]] < a[b[i+1]] a. Dar un algoritmo que resuleva el problema, y programarlo en imperativo. b. Dar el invariante del ciclo c. Reescribir la especificacin del problema con una lista de entrada y una de salida. Programar el mismo algoritmo que en punto b, en funcional. Respuesta no incluida Ejercicio 22 Dado un programa en Haskell que imlementa una funcin total f:N-> N inyectiva. a. Dar el elgoritmo que que resuelve la inversa de f, y programarlo en Haskell. Ayuda: usar f() como fucin auxiliar. b. Demostrar la correctitud de la solucin. Respuesta Algoritmo para computar la funcin inversa de f : N ! N inyectiva. Buscar linealmente x, empezando por x igual a 1, hasta que se cumpla la condicin f (x) == y. Programa Haskell. La funcin f pasa como argumento. inversa :: (Int ! Int) ! Int ! Int inversa f y = bl f y 1 bl:: (Int!Int) ! Int ! Int ! Int bl f y x | ((f x) == y) = x | otherwise = bl f y (x+1) problema inversa (f :Int ! Int, y:Int): x:Int { requiere y " 1 requiere !v "!u (v>0 # (u>0 and ((f u)==v)) asegura ((f x) == y) } inversa f y realiza la bsqueda lineal en los nmeros naturales, empezando por el 1, hasta encontrar el nmero natural x tal que (f x)==y. Si y tiene una preimagn, entonces inversa f y est definido. En caso contrario, inversa f y queda indefinido. Ejercicio 23 Dado el siguiente programa en C++. (Opcional porque es un poco oscuro, pero si lo entienden es divertido) void bbs(int a[], int n){ listo=false; while (!listo){ listo=swap_consecutivos(a,n); } Se pide: 1.Hacer el seguimiento de los estados por los que pasa la ejecucin de bbs([8,1,4,2,5], 5) . 2.Dar una expresin variante decreciente y acotada del ciclo de la funcin bbs. (Ayuda: observar que en cada iteracin el arreglo a[ ] pasa a tener un segmento final definitivo de tamao mayor que el del paso anterior. Dar la postcondicion de swap_consecutivos teniendo esto en cuenta. 3.Especificar un problema para el cual la funcin bbs es correcta.

8/9

bool swap_consecutivos(int a[], int n){ int sin_cambios=true; int i=0; while (i<= n 2){ if (a[i] > a[i+1]){ swap(a[i], a[i+1]); sin_cambios=false; } i++; } return sin_cambios; } Respuesta Q_swap_cons: mismos(a,pre(a)) ^ res == ordenado(pre(a)) ^ max_ord(a) >= max_ord(pre(a)) + beta( not(ordenado(pre(a)))) aux max_ord(b) = | [ j | j <-[1..|b|], ordenado(b[ |b|-j.. |b|) ) ] | aux ordenado(b) = todos( b[ j ] <= b[ j+1] | j<-[ 0.. |b|-1)] ) aux mismos(a,b) = |a| ==|b| ^ paratodo k<-[0..|a|) cuenta(a[k], a) ==cuenta(a[k],b) fv_bbs = n+1 -max_ord(a) - beta(listo)!

9/9

También podría gustarte