Lo que vas a aprender
- Qué cuenta como operación elemental.
- Las reglas para secuencias, condicionales y bucles.
- Los bucles anidados, dependientes y logarítmicos.
- Cómo analizar la recursión.
- El coste oculto de las operaciones de las estructuras de datos.
- La complejidad espacial.
Fundamentos teóricos
Operaciones elementales
Las que tardan un tiempo constante, : asignaciones, operaciones aritméticas, comparaciones, acceso a un elemento de un array por índice, llamar a una función (sin contar lo que hace dentro).Reglas básicas
Bucles típicos
La clave de los bucles logarítmicos: la variable se multiplica o divide por una constante en cada vuelta, en lugar de sumar.
Recursión
Se escribe una recurrencia con el coste de cada llamada y el de las llamadas que hace:
Las del tipo se resuelven con el teorema maestro (ver divide y vencerás).
El coste oculto de las estructuras de datos
Una sola línea puede esconder un bucle:Complejidad espacial
La memoria adicional que usa el algoritmo. Una lista auxiliar de tamaño es ; una matriz , . La recursión también ocupa memoria: cada llamada pendiente está en la pila, así que una recursión de profundidad usa .Qué tamaños son abordables
En un ordenador se hacen del orden de – operaciones sencillas por segundo:Ejemplos resueltos
Ejemplo 1 · Dos bucles seguidos
Ejemplo 1 · Dos bucles seguidos
Ejemplo 2 · Un 'in' dentro de un bucle
Ejemplo 2 · Un 'in' dentro de un bucle
vistos = [] por vistos = set(), el in pasa a y el total a : un cambio de una línea divide el tiempo por miles con muchos datos.Ejemplo 3 · Bucle logarítmico
Ejemplo 3 · Bucle logarítmico
Ejemplo 4 · Bucle dependiente
Ejemplo 4 · Bucle dependiente
Ejemplo 5 · Recursión con una rebanada
Ejemplo 5 · Recursión con una rebanada
a[1:] copia la lista: , que da en tiempo y en memoria total copiada. Pasando un índice en lugar de rebanar, baja a .Ejemplo 6 · ¿Cuánto tardará?
Ejemplo 6 · ¿Cuánto tardará?
Un algoritmo tarda 1 s con . Con : veces más, unos 100 s. Uno que tarde 1 s con datos tardaría unos 12,5 s con .
Errores frecuentes
- Contar las líneas en vez de las vueltas. Un
in, unsorto una rebanada en una línea pueden ser o más. - Multiplicar bucles que van uno detrás de otro. Se suman; solo se multiplican si están anidados.
- Decir que un bucle de 1000 vueltas fijas es . Si no depende de la entrada, es .
- Olvidar la memoria de la pila en la recursión.
- Confundir el mejor caso con el coste del algoritmo. Se suele dar el peor caso.
Preguntas frecuentes
¿Importan las constantes?
¿Importan las constantes?
En la notación O no, pero en la práctica sí: un algoritmo con una constante enorme puede ser más lento que uno para los tamaños reales. Por eso, para datos pequeños, inserción le gana a merge sort, y las bibliotecas combinan los dos. Lo definitivo es medir.
¿Cómo se mide el tiempo real de un programa?
¿Cómo se mide el tiempo real de un programa?
En Python, con el módulo
timeit o con time.perf_counter() antes y después. Conviene probar con varios tamaños y ver cómo crece: si al duplicar el tiempo se cuadruplica, es cuadrático. El simulador de mejor y peor caso muestra esta idea.Temas relacionados
Notación asintótica
O, Ω y Θ, y recurrencias.
Mejor y peor caso
Cuándo un algoritmo tarda más.
Búsqueda binaria
El ejemplo clásico de O(log n).