Si desea analizar estos algoritmos, debe definir // dostuff, ya que eso realmente puede cambiar el resultado. Supongamos que dostuff requiere un número constante de operaciones O (1).
Aquí hay algunos ejemplos con esta nueva notación:
Para su primer ejemplo, el recorrido lineal: ¡esto es correcto!
EN):
for (int i = 0; i < myArray.length; i++) {
myArray[i] += 1;
}
¿Por qué es lineal (O (n))? A medida que agregamos elementos adicionales a la entrada (matriz), la cantidad de operaciones que ocurren aumenta proporcionalmente al número de elementos que agregamos.
Entonces, si se necesita una operación para incrementar un número entero en algún lugar de la memoria, podemos modelar el trabajo que realiza el ciclo con f (x) = 5x = 5 operaciones adicionales. Para 20 elementos adicionales, hacemos 20 operaciones adicionales. Una sola pasada de una matriz tiende a ser lineal. También lo son los algoritmos como la ordenación de cubetas, que pueden explotar la estructura de datos para hacer una ordenación en una sola pasada de una matriz.
Su segundo ejemplo también sería correcto y se ve así:
O (N ^ 2):
for (int i = 0; i < myArray.length; i++) {
for (int j = 0; j < myArray.length; j++) {
myArray[i][j] += 1;
}
}
En este caso, por cada elemento adicional en la primera matriz, i, tenemos que procesar TODO j. Agregar 1 a i en realidad agrega (longitud de j) a j. Por lo tanto, tienes razón! Este patrón es O (n ^ 2), o en nuestro ejemplo en realidad es O (i * j) (o n ^ 2 si i == j, que a menudo es el caso con operaciones matriciales o una estructura de datos cuadrada.
Su tercer ejemplo es donde las cosas cambian dependiendo del dostuff; Si el código está escrito y hacer cosas es una constante, en realidad es solo O (n) porque tenemos 2 pases de una matriz de tamaño n, y 2n se reduce a n. Los bucles que se encuentran uno fuera del otro no son el factor clave que puede producir un código 2 ^ n; Aquí hay un ejemplo de una función que es 2 ^ n:
var fibonacci = function (n) {
if (n == 1 || n == 2) {
return 1;
}
else {
return (fibonacci(n-2) + fibonacci(n-1));
}
}
Esta función es 2 ^ n, porque cada llamada a la función produce DOS llamadas adicionales a la función (Fibonacci). Cada vez que llamamos a la función, la cantidad de trabajo que tenemos que hacer se duplica ¡Esto crece súper rápido, como cortar la cabeza de una hidra y hacer que broten dos nuevas cada vez!
Para su ejemplo final, si está utilizando una ordenación nlgn como merge-sort, tiene razón en que este código será O (nlgn). Sin embargo, puede explotar la estructura de los datos para desarrollar tipos más rápidos en situaciones específicas (como en un rango de valores conocido y limitado, como 1-100). Sin embargo, tiene razón al pensar que domina el código de orden superior; entonces, si una ordenación O (nlgn) está al lado de cualquier operación que tome menos tiempo de O (nlgn), la complejidad del tiempo total será O (nlgn).
En JavaScript (al menos en Firefox), la ordenación predeterminada en Array.prototype.sort () es de hecho MergeSort, por lo que está buscando O (nlgn) para su escenario final.