Primero, tenga en cuenta que [matemáticas] O (n) [/ matemáticas] y [matemáticas] O (2n) [/ matemáticas] son la misma cosa . No entraré en detalles, pero debes saber que [math] O \ left (f (n) \ right) [/ math] denota el conjunto de funciones que crecen más lentamente que [math] f (n) [/ math] , asintóticamente hablando . Y [matemáticas] O (2n) [/ matemáticas] crece tan rápido como [matemáticas] O (n) [/ matemáticas], asintóticamente hablando, porque el análisis asintótico no se preocupa por factores constantes ([matemáticas] 2 [/ matemáticas] , en este caso).
Ahora a la pregunta principal: no existe una receta universal para evaluar la complejidad teórica de un algoritmo. A veces, esta tarea puede resultar muy difícil. La buena noticia es que una amplia gama de algoritmos prácticos son fáciles de analizar. Por ejemplo, si su algoritmo está compuesto por for-loops, todo lo que tiene que hacer es evaluar sumas sobre rangos.
Tomemos, por ejemplo, un programa compuesto por un bucle con iteraciones [matemáticas] n [/ matemáticas] que funciona [matemáticas] O (i) [/ matemáticas] en cada iteración. En este caso, la complejidad de su programa estará dada por [math] \ displaystyle \ sum_ {i = 1} ^ {n} {i} = \ frac {n (n + 1)} {2} = O (n ^ 2 )[/matemáticas]. Puede componer diferentes sumas para evaluar la complejidad de programas más grandes. En particular, los bucles for anidados corresponden a sumas anidadas, y dos bucles for secuenciales corresponden a la suma de dos sumas diferentes.
- ¿Por qué obtengo el índice de cadenas fuera de rango?
- ¿Por qué la notación Big-O es una forma muy útil de analizar la complejidad del algoritmo?
- ¿Qué sitio web / tutorial / video puedo usar para comprender muy bien la programación dinámica en un día?
- Dada una serie de dígitos, ¿cómo los clasifica con la complejidad temporal o (n)?
- ¿Cómo ayuda la selección de estructuras de datos apropiadas para diseñar mejores algoritmos?
Agregue bucles while con condiciones de detención más que triviales y el problema se vuelve mucho más difícil. Considere el caso del siguiente programa:
- Mientras [math] n \ neq 1 [/ math]:
- Si [math] n [/ math] es par, [math] n: = n / 2 [/ math]
- Si [math] n [/ math] es impar, [math] n: = 3n + 1 [/ math]
Este es un programa muy simple con una condición de detención muy simple y, sin embargo, si de alguna manera lograste proporcionar un límite superior a su complejidad, habrías resuelto efectivamente un famoso problema abierto en matemáticas, la Conjetura de Collatz.
No se pierde toda esperanza: en la mayoría de los casos, es bastante fácil proporcionar un límite superior suelto a la complejidad de su programa, incluso si no puede evaluar el límite más estricto (lo cual es preferible). Y si incluso eso le falla, siempre puede recurrir a un análisis empírico y utilizar la regresión lineal para adaptar la complejidad de su solución a alguna hipótesis típica (logarítmica, polinómica, exponencial, etc.). Además de proporcionar soporte estadístico, esto puede brindarle información sobre la complejidad teórica de su algoritmo, y luego puede proceder a evaluarlo analíticamente (es más fácil derivar la complejidad de un algoritmo cuando ya conoce el resultado final).