Actividad integradora 6 CREAR UN RECURSO MULTIMEDIA
Tema 2 eficiencia_y_complejidad_grupo_21
1. Análisis y Diseño
de Software
Tema 2b. Eficiencia y
Complejidad
Carlos A. Iglesias <cif@gsi.dit.upm.es>
Departamento de Ingeniería de Sistemas Telemáticos
http://moodle.dit.upm.es
G21
2. Legenda
Teoría
Ejercicio práctico en el ordenador / Problema
Ampliación de conocimientos
Lectura / Vídeo / Podcast
Práctica libre / Experimentación
Eficiencia y Complejidad 2
4. Temario
● Complejidad: el problema
● Espacio de problemas
● Notación O (Big O)
● Complejidad de algoritmos básicos de
ordenación y búsqueda
● Evaluar la complejidad de un algoritmo
● Análisis y conclusiones
Eficiencia y Complejidad 4
5. Objetivos
● Entender cómo se pueden comparar
algoritmos
● Entender qué es una medida de
complejidad
● Conocer la notación O
● Conocer la notación O para algoritmos
básicos de ordenación y búsqueda
● Saber razonar con la notación O
Eficiencia y Complejidad 5
6. El problema
● ¿En qué nos
basamos para
seleccionar un
algoritmo cuando
hay tantos
disponibles (y tan
parecidos)?
Eficiencia y Complejidad 6
7. ¿Qué elegir?
● “En casi todos los cálculos,
es posible una gran
variedad en la forma de de
llevar a cabo los procesos
de computación. […] Es
esencial seleccionar la
forma que reduzca al
mínimo el tiempo para
completar un cálculo”
Ada Lovelace
Eficiencia y Complejidad 7
8. ¿Qué elegir?
● El algoritmo más
eficiente
● Eficiencia:
inversamente
proporcional a los
recursos (memoria,
tiempo, …)
consumidos por un
algoritmo
Eficiencia y Complejidad 8
9. Formas de seleccionar
● De forma 'empírica':
– Medimos su recursos consumidos de los
algoritmos (tiempo, memoria, uso de
comunicaciones, disco, consumo energético,
…, caso mejor, peor, medio, …)
● De forma 'analítica' / teórica:
– Calculamos un 'límite' de estos recursos,
analizando el algoritmo y su implementación
Eficiencia y Complejidad 9
10. Medidas empíricas
● Medimos (p.ej. Tiempo).
// Creo el entorno
Algoritmo a = new Algoritmo();
Datos d = new Datos(); // relleno
// Mido
long t1 = System.currentTimeMillis();
a.run(d);
long t2 = System.currentTimeMillis();
long duracion = t2 – 1;
Eficiencia y Complejidad 10
11. Medidas empíricas
● Como los algoritmos son genéricos, las medidas empíricas pueden
verse afectadas por:
– El lenguaje de programación
– El entorno de ejecución / sistema operativo (p.ej. JVM GC, multinúcleo, …)
– Los datos que usemos al medir
● Pueden ayudarnos a entender cómo funcionan, y tenemos que analizar
bien el experimento cuando obtenemos resultados inesperados
● Si medimos, podemos intentar ajustar las gráficas, y ver qué distribución
siguen (polinómico, lineal, etc.). Si estás interesado, mira los apuntes.
Eficiencia y Complejidad 11
12. Medidas teóricas: notación O
(Big O Notation)
● Nos ayuda a clasificar algoritmos según
cómo crezca su respuesta (tiempo de
ejecución, memoria, etc.) con el número de
datos de entrada
● Algoritmos con la misma “respuesta”,
tendrán la misma notación O
● Representa la cota del valor peor que
pueden tomar, el límite superior
Eficiencia y Complejidad 12
13. Órdenes de funciones
comunes
Notación Nombre Comentario
O(1) Constante Ideal
O(log n) Logarítmico Muy bueno
O(n) Lineal normal
O(nlogn) Lineal razonable
logarítmico
O(n2) Cuadrático tratable
O(nc) Potencial “tratable”
O(cn), n >1 Exponencial No es práctico
O(n!) Factorial inviable
Eficiencia y Complejidad 13
15. O(1): complejidad constante
● Complejidad constante, independiente del
tamaño de la entrada
boolean isElementoNulo(Object [] array, int indice) {
if (a[indice] == null) {
return true;
}
return false;
}
boolean isElementoNulo(Object [] array, int indice) {
return (a[indice] == null) {
}
Eficiencia y Complejidad 15
16. O(n): lineal
● Consumo de recursos directamente
proporcional a la entrada
● Ej. búsqueda lineal. Caso peor: buscamos
el último elemento, recorremos n → O(n)
Eficiencia y Complejidad 16
17. Burbuja – notación O
● Si analizamos cuántas comparaciones hacemos
● P. ej para n = 10
– 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 = 45
● En general, para N:
– (N – 1) + (N – 2) + … + 1 = N * (N-1)/2
● Si N es grande, el número será N2
● La notación O : O(N2), cota superior asintótica
Eficiencia y Complejidad 17
18. Burbuja: Complejidad
intercambios
● Si analizamos intercambios, si suponemos
que el conjunto es aleatorio, podemos
suponer que sólo estarán desordenados la
mitad
– Si había N2/2 comparaciones, habría N2/4
intercambios
● Tanto comparaciones como intercambios
son O(N2)
Eficiencia y Complejidad 18
19. Selección: Análisis
● Complejidad:
– Hacemos las mismas comparaciones que en la burbuja: N * (N – 1) /2 →
O(N2)
– Hacemos menos intercambios, menos que N (una pasada) → O(N)
● Para grandes valores de N, pesará más el término de
comparaciones, y la complejidad será O(N 2)
● Para N pequeño, será más rápido que la burbuja
● En general: no es un algoritmo adecuado
● Puede ser bueno si los tiempos de intercambio son altos
Eficiencia y Complejidad 19
20. Inserción: análisis
● Complejidad:
– En la primera pasada, comparamos con 1 carta, en la
segunda con 2, en la tercera con 3, … → 1 + 2 + 3 +
… + N – 1 = N * (N – 1) / 2
– En media, compararemos con la mitad de cartas
ordenadas → N * (N – 1) / 4 → O(N2)
– Número de copias similar al de comparaciones, pero
una copia requiere menos tiempo que un intercambio
– Si los datos ya están ordenados (o casi), sería O(N)
Eficiencia y Complejidad 20
21. Quicksort: Análisis
● Complejidad:
– En la mayor parte de los casos es el más
rápido: O(n * log(n))
Eficiencia y Complejidad 21
22. Análisis complejidad
Mejor Medio Peor
Selección O (n2) O (n2) O (n2)
Inserción O (n) O (n2) O (n2)
Burbuja O (n) O (n2) O (n2)
Quick sort O (n log n) O (n log n) O (n2)
Eficiencia y Complejidad 22
23. ¿Cómo calculamos la
complejidad? (I)
●Analizamos el código
● En sentencias condicionales (if/else-switch),
cogemos la rama 'peor'
●Bucles:
– Si el bucle no depende de n, simplemente es una cte
O(1), que quitamos
– Si el bucle depende de n, tendremos O(n)
– Si tenemos bucles anidados, que dependen de n, si
son dos, tenemos O(n2) (nos sale 1 + 2 + .. = n(n-
1)/2)
Eficiencia y Complejidad 23
24. ¿Cómo calculamos la
complejidad? (II)
●Si el bucle es multiplicativo, es decir, no es
lineal con n:
int c = 1;
Para n = 10:
while (c < n) {
c= 1, c = 2, c = 4, c= 8
sentencias O(1);
En general, vale 2k <= n
c *= 2;
→ k = n * log2(n) → log(n)
}
int c = n;
while (c > 1) { Para n = 10:
sentencias O(1); c= 10, c = 5, c = 2, c= 1
c /= 2; → log(n)
}
Eficiencia y Complejidad 24
25. ¿Cómo calculamos la
complejidad? (II)
●Si combinamos, nos sale O(nlogn):
for (int i = 0; i < n; i++) {
int c = i;
while (c > 0) {
sentencias O(1);
c /= 2;
}
}
Eficiencia y Complejidad 25
29. Caso mejor
600
400
inserción
T (ms)
200 burbuja
Quick + Insert
0 Quick + Insert
inserción
QuickSort
100
500
2.000
10.000
L
Eficiencia y Complejidad 29
30. Tipos de problemas
● Hay muchos problemas que no sabemos
un algoritmo para resolverlos.
● Entre los que sabemos resolver, los tipos
más importantes son:
– Problemas P: Problemas con complejidad
polinómica (O(n), O(n2), etc.)
– Problemas NP: Problemas que no pueden
resolverse en un tiempo polinómico, e
intentamos buscar otro algoritmo.
Eficiencia y Complejidad 30
31. Resumen
● Para elegir un algoritmo, podemos
– Seguir un enfoque empírico, y ver cómo
evolucionan la respuesta del algoritmo con la
entrada
– Seguir un enfoque analítico
● La notación O nos facilita razonar sobre la
eficiencia de un algoritmo
Eficiencia y Complejidad 31
32. Preguntas
● Si pruebo dos algoritmos en mi ordenador, y uno tarda
10 segundos y otro 20 segundos, ¿cuál es más
eficiente?
● Si sé que un algoritmo tiene una respuesta 9n 3 + 2n2 +
4n +2, ¿cuál sería su notación O?
● ¿Qué significa que O es el límite asintótico?
● Si tienes unos algoritmos A, B, C con complejidad O(n),
O(nlogn) y O(n2), ¿en qué orden los escogerías?
● Para cualquier valor de n, será siempre más rápido un
algoritmo O(n)) que uno con O(n2)
Eficiencia y Complejidad 32