ndice: 4.1. Introduccin ... 3 4.2. Anlisis de las estructuras de control . 3 4.2.1. Secuencias . 3 4.2.2. Sentencia condicional (if) .. 4 4.2.3. Bucles para (desde) 4 4.2.4. Llamadas recursivas . . 7 4.2.5. Bucles mientras (while) y repetir (repeat) .. 9 4.3. Uso de un barmetro . 10 4.5. Anlisis del caso medio . 11 4.6. Resolucin de recurrencias 12
Bibliografa: Se ha tomado apuntes de los libros: Fundamentos de algoritmia. G. Brassard y P. Bratley Estructuras de Datos y Algoritmos. R. Hernndez Resumen tema 4 Curso 2007/08 Pgina 3 de 12
Este tema es el ltimo de los pertenecientes a costes y de los que ms ejercicios cortos han entrado en exmenes. Por ello, merece la pena pararse sobre todo en las frmulas para hallar el coste de la recursividad. Nos saltamos el apartado 4.4, que trata de ejemplos adicionales, ya que los iremos incluyendo en el resto del tema. 4.1. Introduccin. El objetivo principal de este libro es ensear a disear algoritmos eficientes. Para resolver el mismo problema con varios algoritmos es preciso decidir cul de ellos es el ms adecuado para la aplicacin considerada, recordemos que eso lo hemos visto en el tema 1. Una herramienta esencial para este propsito es el anlisis de los algoritmos, aunque no tendremos una frmula mgica para hallar la eficiencia de los algoritmos. Existen tcnicas bsicas que suelen resultar tiles, tales como saber la forma de enfrentarse a estructuras de control y a ecuaciones de recurrencia, que ser lo que tratemos en este captulo. Aadiremos en este captulo el anlisis del bucle if para completarlo aun ms.
4.2. Anlisis de las estructuras de control. El anlisis de los algoritmos suele efectuarse desde dentro hacia fuera. Seguiremos estos pasos: - En primer lugar, se determina el tiempo requerido por las instrucciones individuales (suele estar acotado por una constante). - Despus se combinan estos tiempos de acuerdo con las estructuras del programa. En esta seccin ofreceremos unos principios generales que resultan tiles en aquellos anlisis relacionados con las estructuras de control de uso ms frecuente, as como ejemplos de la aplicacin de estos principios (para mientras,).
4.2.1. Secuencias. Sean P 1 y P 2 dos fragmentos de un algoritmo (instrucciones o subalgoritmos). Sean t 1 y t 2 los tiempos requeridos por P 1 y P 2 , respectivamente. Estos tiempos pueden depender de distintos parmetros tales como el tamao del caso. La regla de la composicin secuencial dice que el tiempo necesario para calcular "P 1 ; P 2 ", esto es, primero P 1 y despus P 2 , es simplemente t 1 +t 2 . Por la regla del mximo este tiempo est en 0(mx(t 1 ,t 2 )), es decir, como vimos previamente el coste del algoritmo lo determinar el ms ineficiente. Ejemplo:
P 1 t 1 (n) P 2 t 2 (n) _ t(n) =t 1 (n) +t 2 (n) siendo: t 1 (n): Lo que cuesta la primera funcin. t 2 (n): Lo que cuesta la segunda funcin. Resumen tema 4 Curso 2007/08 Pgina 4 de 12
El coste del algoritmo, siguiendo la regla del mximo ser: t(n) 0 [mx(t 1 (n), t 2 (n))
4.2.2. Sentencia condicional (if). Este aadido es del autor. Tenemos la siguiente sentencia condicional: si B entonces S 1
si no S 2
fsi
Tenemos estos costes: si B 0( 0 (n)) si S 1 0( 1 (n)) si S 2 0( 2 (n))
La cota superior ser: 0[mx( 0 (n), 1 (n), 2 (n)) (camino mximo). La cota inferior ser: 0[min( 0 (n), 1 (n), 2 (n)) (camino mnimo).
4.2.3. Bucles para (desde). Los bucles (lazos) para (desde) son los ms fciles de analizar. Considrese el bucle siguiente: para i 1 hasta m hacer P(i) Se nos dan varios casos: a. El tiempo (t(n)) requerido por P(i) no depende realmente de i, an cuando pudiera depender del tamao del ejemplar o del ejemplar en s. Es el caso ms sencillo. En este caso, el tiempo total requerido por el bucle es simplemente l =m t o bien I(n) =m t(n). Se haran m iteraciones y cada uno con el mismo coste. Sera algo as como este bucle mientras: i 1; mientras i <m hacer P(i); i i +1; Asignaremos costes unitarios (operaciones elementales) a la comprobacin i <m, a las instrucciones i 1 e i i +1 y a las instrucciones de salto implcitas en el bucle mientras. Se demuestra que este tiempo al hacer las operaciones est acotado superiormente por m t, tal como habamos escrito antes.
Resumen tema 4 Curso 2007/08 Pgina 5 de 12
b. El tiempo (t(n)) requerido por P(i) vara como funcin de i. Si despreciamos el tiempo requerido por el bucle de control, para m 1, entonces ese mismo bucle para requiere un tiempo que est dado por una suma t(i) m =1 . Sera entonces I(n) = t(i,n) m =1 el coste del bucle.
Ejemplo: Analizamos el coste de este bucle para: funcion fibiter(n) i 1; ] 0; para k 1 hasta n hacer ] i +]; i ] i; fpara devolver j ffuncion Se nos darn dos casos en funcin de los costes de las operaciones aritmticas: 1. Las operaciones aritmticas se consideran como de coste unitario. Las instrucciones de dentro del bucle para requieren un tiempo constante. Suponemos que el tiempo requerido por estas instrucciones est acotado superiormente por alguna constante c. El tiempo requerido por el bucle para est acotado superiormente por n veces esta constante: n*c. El algoritmo tiene coste 0(n). 2. Las operaciones aritmticas no se consideran como de coste unitario. Podemos llegar a ver como al paso del bucle se vuelve costosa una instruccin tal como ] i +], por haber operandos muy grandes. Sea c una constante tal que este tiempo est acotado superiormente por c k para todo k 1. Si despreciamos el tiempo requerido por el control del bucle y las instrucciones que preceden al bucle concluiremos que el tiempo requerido por el algoritmo est acotado superiormente por: c k =c k = n k=1 n k=1 c n(n+1) 2 0(n 2 ) Un razonamiento similar indica que este tiempo se encuentra en (n 2 ) y se deduce, por tanto, que est en 0(n 2 ).
El anlisis del bucle para que empiezan en un valor que no sea 1 o que avanzan con pasos mayores, debera resultar evidente. Ejemplo: Se nos da el siguiente bucle: para i 5 hasta m paso 2 hacer P(i) Aqu, P(i) se ejecuta ((m 5) 2) +1 veces siempre que m 3. Resumen tema 4 Curso 2007/08 Pgina 6 de 12
Ejemplo completo de anlisis de un algoritmo con bucle para. Para ello, analizaremos la ordenacin por seleccin: procedimiento seleccionar(I(1..n)) para i 1 hasta n 1 hacer min] 1; mink I[i]; para ] i +1 hasta n hacer si I[]] <minx entonces min] ]; mink I[]]; fsi fpara I[min]] I[i]; I[i] minx; fpara fprocedimiento Seguiremos estos pasos: 1. Anlisis de su funcionamiento: Dentro del bucle para exterior tendremos uno interior que nunca sabremos si realiza las mismas instrucciones con el mismo coste. Estaremos en el caso b) de los vistos anteriormente. i
Parte ordenada Parte desordenada
La idea bsica es seleccionar el menor elemento de una parte desordenada del vector y colocarlo en la posicin del primer elemento no ordenado. En un primer paso, se recorre el vector hasta encontrar el elemento menor. Para ello se coloca el primer elemento en una variable temporal y se va comparando con los dems elementos del vector tal que si se encuentra uno menor se asigna a la variable temporal. Recorrido todo el vector, el elemento de la variable temporal (que ser el menor) se intercambia con el de la primera posicin (el primero escogido de la parte desordenada). Seguidamente, se considera nicamente la parte del vector no ordenado y se repite el proceso de bsqueda del menor, y as sucesivamente. Se puede describir de la siguiente manera: Seleccionar el elemento menor de la parte del vector no ordenada. Colocarlo en la primera posicin de la parte no ordenada del vector. El coste es independiente de cmo vienen ordenados los datos, es decir, del contenido de los datos.
Resumen tema 4 Curso 2007/08 Pgina 7 de 12
2. Anlisis del coste: Veremos el nmero de instrucciones y analizaremos el coste del algoritmo en el caso peor, como es habitual: procedimiento seleccionar(I(1..n)) (1) para i 1 hasta n 1 hacer min] 1; mink I[i]; (2) para ] i +1 hasta n hacer si I[]] <minx entonces (3) min] ]; mink I[]]; fsi fpara I[min]] I[i]; I[i] minx; fpara fprocedimiento
Suponemos que las operaciones de suma, asignacin, son elementales, por tanto, no las consideraremos en el coste total del algoritmo. Pasamos a ver el nmero de instrucciones en cada paso: (1) n iteraciones coste n (2) (n i) iteraciones Tendremos que el bucle para interior y el si tendrn el siguiente nmero de instrucciones: (2) +(3) I(n) (n i) n =1 . Resolviendo la sucesin, tendremos que I(n) (n i) n =1 =(n 1) (n 2) 1 n 2 . Como conclusin, el coste en todos los casos es O(n 2 ).
4.2.4. Llamadas recursivas. El anlisis de algoritmos recursivos suele ser sencillo. Una inspeccin sencilla del algoritmo suele dar lugar a una ecuacin de recurrencia que imita el flujo de control dentro del algoritmo. Una vez que se ha obtenido la ecuacin de recurrencia, se pueden aplicar las tcnicas generales para resolverlas.
Resumen tema 4 Curso 2007/08 Pgina 8 de 12
Ejemplo: Considrese el algoritmo recursivo siguiente: funcion fibrec (n) si n <2 entonces devolver n si no devolver fibrec (n 1) +fibrec (n 2)
Sea I(n) el tiempo requerido por una llamada a fibrec (n): - Si n <2, el algoritmo devuelve simplemente n, lo cual requiere un tiempo constante a. - En caso contrario, la mayor parte del trabajo se invierte en dos llamadas recursivas, que requieren un tiempo I(n 1) y I(n 2), respectivamente.
Sea (n) el trabajo implicado en esta suma y en este control, es decir, el tiempo requerido por una llamada a fibrec(n) ignorando los tiempos invertidos dentro de las dos llamadas recursivas. Por definicin de I(n) y de (n), obtenemos la siguiente recurrencia:
o Si n =0 n =1 (n <2) I(n) = I(n 1) +I(n 2) +(n) En caso contrario
Trataremos, por tanto, estos casos: - Si contamos las sumas con coste unitario, (n) est acotado por una constante y la ecuacin de recurrencia es similar a la ya encontrada antes. Tenemos que I(n) 0((n)), razonando de manera similar para la cota inferior. Concluimos, entonces, que fibrec (n) requiere un tiempo exponencial en n. - Si no se cuentan las adiciones con un coste unitario, (n) ya no queda acotado por una constante. (n) est dominado por la adicin de n-1 y n-2 para n suficientemente grande. La adicin requiere un tiempo (n) 0((n)).
Deducimos que el resultado es el mismo independientemente de si (n) es constante o lineal: I(n) 0((n)). La nica diferencia es la constante multiplicativa oculta en la notacin 0.
Resumen tema 4 Curso 2007/08 Pgina 9 de 12
4.2.5. Bucles mientras (while) y repetir (repeat). Para analizar estos bucles no existe una forma evidente a priori de saber cuntas veces tendremos que pasar por el bucle. Podremos emplear dos tcnicas: - Es la tcnica estndar. Es hallar una funcin de las variables implicadas cuyo valor se decremente en cada pasada. - Para determinar el nmero de veces que se repite el bucle necesitamos conocer mejor la forma en que disminuye el valor de esta funcin. Para analizar el bucle mientras de manera alternativa consiste en tratarlo como un algoritmo recursivo.
Ejemplo: Estudiaremos con detalle el algoritmo de bsqueda binaria. funcion busq_binaria(I[1..n],x) i 1; ] n; mientras i <] hacer k (i +]) 2; caso_de x <I[k]: ] k 1; x =I[k]: i, ] k; {Jc:ol:cr k} x >I[k]: i k +1; fcaso fmientras dev i; ffuncion
Analizaremos el algoritmo siguiendo los pasos anteriores: 1. Anlisis del funcionamiento:
j i
k
La idea bsica que subyace a la bsqueda binaria es comparar x con el elemento k que est en la posicin media de T. El objetivo de la bsqueda binaria es hallar un elemento x de un vector I[1..n] que est ordenado de modo no decreciente (slo podremos aplicar la bsqueda binaria si este vector est ordenado as). Supongamos por sencillez que est garantizado que x aparece al menos una vez en T. Se nos pide buscar un entero i tal que 1 i n y I[i] =x. Como el elemento k est en el centro del vector se dan tres casos: - Elemento x est a la izquierda de k. - Elemento x coincide con k. - Elemento x est a la derecha de k. Resumen tema 4 Curso 2007/08 Pgina 10 de 12
Mediante sucesivas divisiones por 2 llegaremos hasta que i =]. En el primer caso, en el que x sea menor que la mitad moveremos el puntero j a la mitad izquierda. En el ltimo caso, moveremos el puntero i. El caso intermedio, sera ya la solucin, encontrando el elemento x. Para resolverlo definiremos d como el nmero de posiciones donde podr ir el elemento: J =] i +1 En el paso inicial, consideramos las n posiciones: J ` =[ +] 2 1 i +1= ]- 2
d 2 . Hemos sustituido j por su mitad, es decir, ] =k 1 = +] 2 para el caso x <I[k] (elemento en la mitad izquierda). El significado de las variables hasta el momento es el siguiente: d: Representa los valores de ] i +1 antes del bucle mientras. J ` : Representa el nmero de iteraciones tras finalizar el bucle, antes de la siguiente iteracin. Para el caso x >I[k] (elemento en la mitad derecha), tenemos que k = +] 2 . Sustituyendo, como vimos previamente: J ` =] [ +] 2 1 +1 = ]- 2
d 2 . El coste ser O(|ug(n)), porque siempre se divide por 2 para buscar el elemento.
4.3. Uso de un barmetro. Definicin: Una instruccin barmetro es aqulla que se ejecuta por lo menos con tanta frecuencia como cualquier otra instruccin del algoritmo. Siempre que el tiempo requerido por cada instruccin est acotado por una constante, el tiempo requerido por el algoritmo completo es del orden exacto del nmero de veces que se ejecuta la instruccin barmetro.
Resumen tema 4 Curso 2007/08 Pgina 11 de 12
Ejemplo: analizaremos el siguiente algoritmo: funcion fibiter(n) i 1; ] 0; para k 1 hasta n hacer ] i +]; i ] i; fpara devolver j ffuncion Podremos considerar que la instruccin ] i +] se puede tomar como un barmetro, por ser ejecutada un nmero de veces igual a n. Se ve entonces que el algoritmo requiere un tiempo que est en 0(n). Cuando un algoritmo contiene varios bucles anidados, toda instruccin del bucle ms interno puede utilizarse en general como barmetro. Sin embargo, hay que hacer esto con cuidado, porque hay casos en los que es preciso tener en consideracin el control implcito del bucle. Esto sucede cuando algunos de los bucles se ejecutan cero veces.
4.5. Anlisis del caso medio. Requiere suponer a priori una distribucin de probabilidad para los casos en que se pedir que resuelva nuestro algoritmo.
Resumen tema 4 Curso 2007/08 Pgina 12 de 12
4.6. Resolucin de recurrencias. Tendremos dos tipos: - Reduccin por sustraccin: La ecuacin de la recurrencia es la siguiente:
c n k si 0 n <b I(n) = o I(n b) +c n k si n b
La resolucin de la ecuacin de recurrencia es:
0(n k ) si o <1 I(n) = 0(n k+1 ) si o =1 0(o n d b ) si o >1
- Reduccin por divisin: La ecuacin de la recurrencia es la siguiente:
c n k si 1 n <b I(n) = o I(n/ b) +c n k si n b
La resolucin de la ecuacin de recurrencia es:
0(n k ) si o <b k
I(n) = 0[n k log(n) si o =b k
0(n Iog b u ) si o >b k
siendo: a: Nmero de llamadas recursivas. b: Reduccin del problema en cada llamada. c n k : Todas aquellas operaciones que hacen falta adems de las de recursividad.