Se você deseja analisar esses algoritmos, precisa definir // dostuff, pois isso pode realmente mudar o resultado. Suponhamos que o dostuff exija um número O (1) constante de operações.
Aqui estão alguns exemplos com esta nova notação:
Para o seu primeiro exemplo, a travessia linear: isso está correto!
EM):
for (int i = 0; i < myArray.length; i++) {
myArray[i] += 1;
}
Por que é linear (O (n))? À medida que adicionamos elementos adicionais à entrada (matriz), a quantidade de operações acontecendo aumenta proporcional ao número de elementos que adicionamos.
Portanto, se for necessária uma operação para incrementar um número inteiro em algum lugar da memória, podemos modelar o trabalho que o loop realiza com f (x) = 5x = 5 operações adicionais. Para 20 elementos adicionais, fazemos 20 operações adicionais. Uma única passagem de uma matriz tende a ser linear. O mesmo ocorre com algoritmos como a classificação de bucket, que são capazes de explorar a estrutura dos dados para fazer uma classificação em uma única passagem de uma matriz.
Seu segundo exemplo também estaria correto e terá a seguinte aparência:
O (N ^ 2):
for (int i = 0; i < myArray.length; i++) {
for (int j = 0; j < myArray.length; j++) {
myArray[i][j] += 1;
}
}
Nesse caso, para cada elemento adicional na primeira matriz, temos que processar TODOS os j. A adição de 1 a i adiciona (comprimento de j) a j. Assim, você está correto! Esse padrão é O (n ^ 2), ou, no nosso exemplo, é realmente O (i * j) (ou n ^ 2 se i == j, o que geralmente acontece com operações de matriz ou uma estrutura de dados quadrada.
Seu terceiro exemplo é onde as coisas mudam, dependendo do material; Se o código é como está escrito e o material é uma constante, na verdade é apenas O (n) porque temos 2 passagens de uma matriz de tamanho n, e 2n reduz-se a n. Os loops que estão fora um do outro não é o fator chave que pode produzir código 2 ^ n; Aqui está um exemplo de uma função que é 2 ^ n:
var fibonacci = function (n) {
if (n == 1 || n == 2) {
return 1;
}
else {
return (fibonacci(n-2) + fibonacci(n-1));
}
}
Esta função é 2 ^ n, porque cada chamada para a função produz DUAS chamadas adicionais para a função (Fibonacci). Toda vez que chamamos a função, a quantidade de trabalho que temos que fazer dobra! Isso cresce super rápido, como cortar a cabeça de uma hidra e ter duas novas brotando a cada vez!
Para o seu exemplo final, se você estiver usando uma classificação nlgn como merge-sort, está certo de que esse código será O (nlgn). No entanto, você pode explorar a estrutura dos dados para desenvolver classificações mais rápidas em situações específicas (como em um intervalo conhecido e limitado de valores, como de 1 a 100). Você está certo ao pensar, no entanto, que o código de ordem mais alta domina; portanto, se uma classificação O (nlgn) estiver próxima a qualquer operação que leve menos que O (nlgn), a complexidade total do tempo será O (nlgn).
Em JavaScript (pelo menos no Firefox), a classificação padrão em Array.prototype.sort () é de fato MergeSort, portanto, você está olhando O (nlgn) para o seu cenário final.