edubun
Português

Quão rápido? Notação O grande

A um bilhão de passos por segundo, um método n² com um milhão de valores leva cerca de 17 minutos; um método n log n leva 0.02 segundo.

O crescimento importa mais que a contagem exata

Até agora contamos os passos com exatidão: 45 comparações, 4 trocas, 20 verificações. Contagens exatas são úteis em exemplos pequenos, mas dependem de detalhes, como se o bubble sort para antes ou como o pivô é escolhido. Quando a entrada fica grande, uma coisa domina todo o resto: como a contagem cresce à medida que n cresce. Um algoritmo cujos passos crescem como n² vai acabar perdendo para um cujos passos crescem como n log n, por mais bem ajustado que o primeiro esteja.

A notação O grande (Big O) é a forma abreviada de descrever esse crescimento. Escrever que um algoritmo é O(n²), que se lê "O grande de n ao quadrado", quer dizer que, para n grande, a contagem de passos dele é no máximo uma constante vezes n². Duas regras facilitam o uso. Descarte os fatores constantes: 3n e n/2 são ambos O(n). Fique só com o termo que cresce mais rápido: n²/2 − n/2, as comparações do selection sort, é O(n²), porque para n grande a parte n² é quase tudo. O curso 6.006 do MIT usa a mesma ideia quando compara estruturas de dados e métodos de ordenação pelo tempo de execução assintótico.

As taxas de crescimento comuns

  • O(1), constante. O trabalho não depende de n: ler o primeiro valor de uma lista, ou um valor numa posição conhecida.
  • O(log n), logarítmica. Cada passo corta o problema ao meio: busca binária. Um milhão de valores, cerca de 20 passos.
  • O(n), linear. Cada valor é tratado uma vez: busca linear, achar o maior valor, somar uma lista.
  • O(n log n). Merge sort, e quicksort em média. O melhor que a ordenação por comparação consegue.
  • O(n²), quadrática. Todos os pares são examinados: bubble sort, selection sort e insertion sort no pior caso, ou dois laços um dentro do outro.
  • O(2ⁿ), exponencial. O trabalho dobra a cada valor a mais: testar todos os subconjuntos de n itens, ou mover n discos na Torre de Hanói.
Carregando

Arraste para girar. Role ou faça pinça para dar zoom.

Seis taxas de crescimento desenhadas nos mesmos eixos. Mova n e ligue a escala logarítmica; a tabela mostra a contagem de passos no seu n e o tempo para um milhão de valores a um bilhão de passos por segundo.

O que os números querem dizer em segundos

Suponha que um computador faça um bilhão (10⁹) de passos básicos por segundo, um número redondo razoável para um núcleo de processador. Veja o que cada taxa de crescimento significa para um milhão de valores. O(log n) dá cerca de 20 passos, bem menos de um microssegundo. O(n) dá um milhão de passos, um milissegundo. O(n log n) dá cerca de 20 milhões de passos, 0.02 segundo. O(n²) dá 10¹² passos, mil segundos, cerca de 17 minutos. O(2ⁿ) não pode ser concluído: 2 elevado a um milhão é um número com mais de 300 000 algarismos. É por isso que escolher o algoritmo certo costuma importar muito mais do que comprar um computador mais rápido. Uma máquina dez vezes mais rápida transforma 17 minutos em 1.7 minuto; trocar O(n²) por O(n log n) transforma isso num quinquagésimo de segundo.

CrescimentoPassos para n = 1 000 000Tempo a 10⁹ passos por segundo
O(1)1cerca de um nanossegundo
O(log n)cerca de 20cerca de 20 nanossegundos
O(n)1,000,0001 milissegundo
O(n log n)cerca de 20 000 000cerca de 0.02 segundo
O(n²)1,000,000,000,000cerca de 17 minutos
O(2ⁿ)mais de 300 000 algarismosnunca termina

Lendo a notação O grande no código

Muitas vezes dá para ler a taxa de crescimento direto na forma do código. Um único laço sobre a lista é O(n). Dois laços, um dentro do outro, ambos sobre a lista, são O(n²): para cada uma das n voltas de fora, o laço de dentro faz até n voltas. Um laço que corta um número ao meio a cada vez, como while (n > 1) n = Math.floor(n / 2), é O(log n): partindo de 1000 ele roda 9 vezes, de um milhão 19 vezes. Passos que acontecem um depois do outro se somam, e vence o termo maior: um laço O(n) seguido de um laço O(n²) é O(n²) no total.

// O(n): uma passada
let total = 0;
for (const x of list) total += x;

// O(n²): todos os pares
for (let i = 0; i < list.length; i++)
  for (let j = i + 1; j < list.length; j++)
    if (list[i] === list[j]) console.log("duplicate", list[i]);

// O(log n): cortes ao meio
let k = list.length, rounds = 0;
while (k > 1) { k = Math.floor(k / 2); rounds++; }

Melhor caso, caso médio e pior caso

Um algoritmo pode se comportar de modos muito diferentes em entradas diferentes. O insertion sort é O(n) numa lista já ordenada e O(n²) numa invertida. O quicksort é O(n log n) em média e O(n²) com pivôs ruins o tempo todo. Quando alguém cita uma única notação O grande sem dizer qual caso, em geral está falando do pior caso, porque ele é uma garantia: o algoritmo nunca vai fazer pior que isso. A notação O grande também deixa coisas de fora. Ela ignora os fatores constantes, então, em entradas pequenas, um método O(n²) com passos muito simples pode vencer um O(n log n). É por isso que muitas rotinas de ordenação de verdade passam para o insertion sort nos pedaços curtos da lista.

A notação O grande pode descrever a memória além do tempo. O merge sort usa O(n) de memória extra para a sua segunda lista; o insertion sort usa O(1) de memória extra, só algumas variáveis.
O grandeComo a contagem de passos cresce com n, ignorando os fatores constantes
O(1)Constante: o mesmo trabalho para qualquer n
O(log n)Logarítmica: corta ao meio a cada passo, como na busca binária
O(n)Linear: uma passada pela entrada
O(n log n)Merge sort; o melhor para a ordenação por comparação
O(n²)Quadrática: todos os pares, dois laços aninhados
O(2ⁿ)Exponencial: dobra a cada item a mais
pior casoUma garantia: o algoritmo nunca faz mais do que isso
  1. Quanto é 3n² + 5n + 2 na notação O grande?
    • O(n)
    • O(n²)
    • O(3n²)
    • O(n² + n)
  2. Dois laços, um dentro do outro, cada um percorrendo n valores. Qual é a notação O grande?
    • O(n)
    • O(2n)
    • O(n²)
    • O(log n)
  3. A busca binária é
    • O(1)
    • O(log n)
    • O(n)
    • O(n log n)
  4. Um método O(n²) leva 2 segundos para 1000 valores. Mais ou menos quantos segundos para 10 000 valores?
  5. Um método O(n) leva 2 segundos para 1000 valores. Mais ou menos quantos segundos para 10 000 valores?
  6. A 10⁹ passos por segundo, quantos segundos levam 10¹² passos (um método n² com um milhão de valores)?
  7. Quantas vezes while (n > 1) n = Math.floor(n / 2) roda quando n começa em 64?
  8. Um programa roda um laço O(n) e depois um laço O(n²). No total ele é
    • O(n)
    • O(n²)
    • O(n³)
    • O(n + 2)
  9. O insertion sort numa lista que já está ordenada é
    • O(1)
    • O(n)
    • O(n log n)
    • O(n²)
  10. Por que um método O(n²) pode vencer um método O(n log n) em entradas pequenas?
    • A notação O grande ignora os fatores constantes, e o método mais simples pode fazer menos por passo
    • A notação O grande está errada para n pequeno
    • n² é menor que n log n para todo n
    • Entradas pequenas estão sempre ordenadas
  11. A memória extra do merge sort é
    • O(1)
    • O(log n)
    • O(n)
    • O(n²)
  12. Ordene estas taxas de crescimento da que cresce mais devagar para a que cresce mais rápido.
Pontos-chave
  • A notação O grande descreve como os passos crescem com n, ignorando fatores constantes e termos menores.
  • Taxas comuns: 1, log n, n, n log n, n², 2ⁿ.
  • Um milhão de valores a 10⁹ passos/s: n log n cerca de 0.02 s, n² cerca de 17 minutos.
  • Um laço é O(n); dois laços aninhados O(n²); cortar ao meio O(log n).
  • Uma notação O grande citada sozinha em geral quer dizer o pior caso.
Fontes deste curso (11)
  • MIT OpenCourseWare 6.006 Introduction to Algorithms, Spring 2020 (Demaine, Ku, Solomon)
  • lecture notes 1 Introduction, 3 Sorting, 9 Breadth-First Search, 10 Depth-First Search (ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/pages/lecture-notes) and Fall 2011 lecture 13 BFS notes (ocw.mit.edu/courses/6-006-introduction-to-algorithms-fall-2011)
  • Cormen, Leiserson, Rivest, Stein, Introduction to Algorithms (MIT Press)
  • with the CLRS-based Khan Academy algorithms unit by Thomas Cormen and Devin Balkcom of Dartmouth (khanacademy.org/computing/computer-science/algorithms: binary search, selection sort analysis, merge sort, quicksort overview and analysis)
  • MacTutor History of Mathematics, Al-Khwarizmi (mathshistory.st-andrews.ac.uk/Biographies/Al-Khwarizmi: word algorithm from the Latin title Algoritmi de numero Indorum)
  • D. E. Joyce, Euclid's Elements Book VII Propositions 1 and 2 (mathcs.clarku.edu/~djoyce/elements/bookVII)
  • Wolfram MathWorld, Merge Sort (mathworld.wolfram.com/MergeSort.html: proposed by John von Neumann in 1945, after Knuth 1998 p. 159)
  • Stanford CS "Tony Hoare: Quicksort" (cs.stanford.edu/people/eroberts/courses/soco/projects/2008-09/tony-hoare/quicksort.html: devised while a student at Moscow State University for Russian-English machine translation with a tape dictionary, programmed in Algol 60 and published 1961; the year 1959 from the Wikipedia Quicksort article and its cited sources)
  • Bodleian Libraries, Ada Lovelace (blogs.bodleian.ox.ac.uk/adalovelace: 1843 paper, Note G Bernoulli numbers)
  • Fourmilab text of Menabrea's Sketch with Lovelace's notes (fourmilab.ch/babbage/sketch.html)
  • Seven Bridges of Konigsberg (Euler 1736) and Tower of Hanoi (Edouard Lucas, 1883) checked against the Wikipedia articles and their cited sources.

Data de verificação: 2026-10-17