11.1 Definição da notação Big O
A notação Big O é uma notação matemática usada para descrever o limite superior do tempo de execução ou do consumo de recursos de um algoritmo, dependendo do tamanho dos dados de entrada. Ela ajuda a determinar como o algoritmo se escala bem e como seu desempenho muda à medida que o volume de dados aumenta.
A notação Big O foca nos aspectos mais significativos do algoritmo, ignorando constantes e termos menos significativos, permitindo concentrar-se no comportamento de longo prazo do algoritmo.
Notações principais:
O(1) — Complexidade constante:
- O tempo de execução do algoritmo não depende do tamanho dos dados de entrada.
- Exemplo: acesso a um elemento de um array por índice.
O(n) — Complexidade linear:
- O tempo de execução do algoritmo depende linearmente do tamanho dos dados de entrada.
- Exemplo: iteração simples por todos os elementos de um array.
O(log n) — Complexidade logarítmica:
- O tempo de execução do algoritmo cresce logaritmicamente com o aumento do tamanho dos dados de entrada.
- Exemplo: busca binária em um array ordenado.
O(n^2) — Complexidade quadrática:
- O tempo de execução do algoritmo depende quadraticamente do tamanho dos dados de entrada.
- Exemplo: ordenação por bolha, ordenação por inserção.
O(2^n) — Complexidade exponencial:
- O tempo de execução do algoritmo depende exponencialmente do tamanho dos dados de entrada.
- Exemplo: solução do problema da mochila por força bruta.
Nota. Você aprenderá mais sobre busca binária, ordenação por bolha e o "problema da mochila" nas próximas aulas.
11.2 Interpretação da notação Big O
Como interpretar e usar a notação Big O?
Ignorando constantes e termos menos significativos: Big O descreve o crescimento da função, ignorando constantes e termos menos significativos. Por exemplo, O(2n) e O(3n) são interpretados como O(n).
Comparação de algoritmos: Big O permite comparar algoritmos por sua eficiência assintótica. Por exemplo, um algoritmo com O(n log n) é mais eficiente que um com O(n^2) para volumes de dados muito grandes.
Análise do pior caso: Big O é geralmente usado para analisar o pior caso do tempo de execução de um algoritmo, permitindo estimar sua complexidade máxima.
Ignorando constantes
Vamos ver exemplos de ignorar constantes e termos menos significativos:
Exemplo 1. Considere duas funções:
f(n) = 3n + 2g(n) = 5n + 1
Ambas as funções têm complexidade linear, pois o termo dominante em cada função é n. Portanto, ambas as funções são interpretadas como O(n), apesar das diferenças nos coeficientes e termos adicionais.
Exemplo 2. Considere duas funções:
f(n) = n^2 + 3n + 4g(n) = 2n^2 + n
Ambas as funções têm complexidade quadrática, pois o termo dominante é n^2. Ambas as expressões são interpretadas como O(n^2), apesar das diferenças nos outros termos e coeficientes.
11.3. Comparação de algoritmos
1. Comparação de algoritmos em volumes de dados muito grandes
Exemplo 1:
- O algoritmo A tem complexidade temporal
O(n^2). - O algoritmo B tem complexidade temporal
O(n log n).
Para valores pequenos de n, o algoritmo A pode ser mais rápido devido a constantes menores, mas para valores grandes de n, o algoritmo B será significativamente mais rápido, pois seu crescimento é logarítmico e não quadrático.
Exemplo 2:
- O algoritmo X tem complexidade temporal
O(n). - O algoritmo Y tem complexidade temporal
O(1).
O algoritmo Y sempre será mais rápido, independentemente do tamanho de n, já que O(1) significa que o tempo de execução do algoritmo não depende do tamanho dos dados de entrada.
2. Análise do pior caso
Exemplo 1:
O algoritmo de ordenação por bolha tem complexidade temporal O(n^2) no pior caso, quando o array está ordenado em ordem inversa. Isso significa que para cada elemento no array será necessário comparar e, possivelmente, trocar com cada outro elemento.
Exemplo 2:
A busca binária tem complexidade temporal O(log n) no pior caso. Isso significa que mesmo no pior caso o número de passos necessários para encontrar um elemento dependerá logaritmicamente do tamanho do array, o que é muito eficiente.
3. Impacto no desempenho e escalabilidade
Exemplo 1:
Se tivermos dois algoritmos para processar dados, um com complexidade temporal O(n^2) e outro com O(n log n), e aumentarmos o tamanho dos dados de 1000 elementos para 10 000 elementos, a diferença no desempenho será significativamente perceptível.
- O algoritmo com
O(n^2)executará aproximadamente 100 000 000 operações para 10 000 elementos. - O algoritmo com
O(n log n)executará cerca de 40 000 operações para 10 000 elementos.
Exemplo 2:
Considere um algoritmo que funciona em O(2^n). Se aumentarmos o tamanho dos dados de entrada de 10 para 20 elementos, o número de operações aumenta exponencialmente.
- Para
n = 10: 2^10 = 1024operações. - Para
n = 20: 2^20 = 1 048 576operações.
Isso mostra como a complexidade exponencial rapidamente se torna impraticável para valores grandes de n.
GO TO FULL VERSION