Este documento introduce conceptos básicos sobre la complejidad algorítmica, incluyendo diferentes tipos de complejidad como la complejidad temporal y espacial. Explica que la complejidad no es un número sino una función, y presenta ejemplos de diferentes algoritmos con su análisis de complejidad en el peor y mejor caso.
2. Complejidad de algoritmos: La complejidad algorítmica es una métrica teórica que se aplica a los algoritmos. Entender la complejidad es importante porque a la hora de resolver muchos problemas, utilizamos algoritmos ya diseñados. Saber valorar su valor de complejidad puede ayudarnos mucho a conocer cómo se va a comportar el algoritmo e incluso a escoger uno u otro.
3. Algoritmo: Podemos entender por algoritmo una secuencia de instrucciones cuyo objetivo es la resolución de un problema.
4. Algoritmo A Algoritmo F Algoritmo B Algoritmo E Algoritmo C Algoritmo D
5. ¿Cuál es mejor? Saber si un algoritmo es mejor que otro puede estudiarse desde dos puntos de vista: Un algoritmo es mejor cuanto tarde menos en resolver un problema. O es mejor cuanta menos memoria necesite.
6. A la idea del tiempo que consume un algoritmo para resolver un problema le llamamos: complejidad temporal. A la idea de la memoria que necesita el algoritmo le llamamos: complejidad espacial.
8. 01 funcionejemplo(n: entero):entero 02 empieza 03 variables: a, j, k enteros 04 para j desde 1 hasta n hacer 05 a=a+j 06 fin para 07 para k desde n hasta 1 hacer 08 a=a-1 09 a=a*2 10 fin para 11 devolvera 12 termina El primer bucle se ejecuta n veces, y en su interior hay una instrucción (la de la línea 5). Eso quiere decir que la línea 5 se ejecuta n veces. Después se ejecuta el segundo bucle, que contiene en su interior dos instrucciones (las de las líneas 8 y 9). Como ese segundo bucle se ejecuta también n veces y tiene dos instrucciones, se realizan 2n instrucciones. Finalmente hay una instrucción en la línea 11 que se ejecuta una sola vez. Por lo tanto, el número de instrucciones que se ejecutan en total son n+2n+1 es decir 3n+1
9. 01 funcion ejemplo2(n: entero):entero 02 empieza 03 variables: a entero 04 a=n*3 05 a=a+2 06 devolver a 07 termina La función ejemplo2 realiza siempre 3 instrucciones (las líneas 4, 5 y 6), independientemente de lo que se le pase como parámetro. Este algoritmo siempre tarda lo mismo para cualquier valor de n.
10. 01 funcion ejemplo3(n:entero): entero 02 empieza 03 variables i, j, k enteros 04 para i=1 hasta n hacer 05 para j=n hasta 1 hacer 06 k=k+j 07 k=k+i 08 fin para 09 fin para 10 devolver k 11 termina La función ejemplo3 tiene dos bucles para anidados. Cada bucle se ejecuta n veces, y en el interior del segundo hay 2 instrucciones. El bucle interior hace que las dos instrucciones se repitan n veces, y el bucle exterior hace que todo eso se repita n veces más. Después hay una última instrucción (la de la línea 10). Así pues, se hacen 2×n×n+1 instrucciones, es decir 2n2+1
11. PEOR CASO, MEJOR CASO No todos los algoritmos son totalmente dependiente de la talla. En la mayor parte de los algoritmos, también influye el propio contenido de los datos. Es posible que para un problema determinado de tamaño n, unas veces el algoritmo tarde más y otras tarde menos, dependiendo de los propios datos de entrada del problema de tamaño n.
12. 01 funcionEstaEn(v: array[1..n] de enteros, x: entero):booleano 02 empieza 03 variables: i:entero, encontrado:booleano; 04 i=1; 05 encontrado=false; 06 mientras(NO(encontrado) Y x<=n) hacer 07 si v[i]==x entonces 08 encontrado=true; 09 fin si 10 i=i+1 11 fin mientras 12 devolver encontrado 13 termina
13. El ejemplo anterior contiene en su interior un bucle mientras que no se ejecuta un número determinado de veces. Si pasamos a esa función un vector de n=100 enteros, y un entero x=17. Es evidente que la talla del problema es n=100, ya que es lo que determina el número de instrucciones que se ejecutarán. Sin embargo, es posible que el valor 17 esté situado en la posición 30 del vector, con lo que el bucle se realizará 30 veces, o quizá en la posición 50, o quizá no esté en el vector, con lo que el bucle se ejecutará n=100 veces, recorriendo todo el vector.
14. Se pueden distinguir dos métricas: qué es lo peor que nos puede pasar para un problema de tamaño n, y qué es lo mejor que nos puede pasar para un problema de tamaño n.
15. Haciendo unas pocas cuentas para el ejemplo anterior. Vemos que en el interior del bucle mientras hay 2 instrucciones (el si y el incremento de i), y en el exterior hay 3, dos antes del mientras y una después.
16. Lo mejor que nos puede pasar es que encontremos el valor x a la primera. En ese caso, el bucle se ejecuta una sola vez. Y por lo tanto el número de instrucciones que realizamos son 3+2=5. Lo peor que puede pasar es que el valor x no se encuentre en el vector, así que el bucle se ejecutará n veces, recorriendo todo el vector. El número de instrucciones que realizamos es 3+2n
17. O Grande (Omicron) Para expresar esto, se utiliza una notación específica: Para este algoritmo, su complejidad en el peor caso es O(2n+3) A esta notación se le denomina "O Grande“ o simplemente "Complejidad en el peor caso"
18. Ω Omega Para el mejor de los casos su complejidad seria: Ω(5) A esta notación se le denomina Omega o "complejidad en el mejor caso".