Comparação Assintótica de Funções É desejável exprimir o consumo de tempo de um algoritmo de uma maneira que não dependa da linguagem de programação, nem dos detalhes de implementação, nem do computador empregado. Para tornar isto possível, é preciso introduzir um modo “grosseiro” de comparar funções, ou seja, utilizar funções matemáticas para exprimir a dependência entre consumo de tempo de um algoritmo e o tamanho de sua entrada. Essa comparação leva em conta a “velocidade de crescimento” das funções. Assim, ela despreza fatores multiplicativos (pois a função 2n², por exemplo, cresce tão rápido quanto 10n²) e despreza valores pequenos do argumento (a função n² cresce mais rápido que 100n, embora n² seja menor que 100n quando n é pequeno). Dizemos que esta maneira de comparar funções é assintótica. Comparações assintóticas desprezam valores pequenos de n pois, para entradas pequenas, até mesmo um algoritmo ruim pode ser bom. Portanto uma função f(n) domina assintoticamente outra função g(n) se existem duas constantes positivas c e n0 (ou m dependendo do autor) tais que, para n ≥ n0, temos que |g(n)| ≤ c × |f(n)| Exemplo: Sejam g(n) = (n + 1)² e f(n) = n² • As funções g(n) e f(n) dominam assintoticamente uma a outra, desde que |(n + 1)²| ≤ 4|n²| para n ≥ 1 e |n²| ≤ |(n + 1)²| para n ≥ 0. Existem três notações básicas para representarmos comparações assintóticas. São elas: Notação O, Notação Ômega e Notação Theta. Notação O Esta notação é utilizada para analisar o pior caso. Uma função f(n) é O(g(n)) (lê-se f(n) é da ordem de g(n)) se ∃ c > 0 e n0 tais que f(n) <= c.g(n) para n >= n0. Explicação: uma função g(n) é da ordem de complexidade de f(n) se existe uma constante c e um valor n0 tal que, para qualquer valor de n maior do que n0 g(n) é menor ou igual a c x f(n). Isso significa que: • f(n) é um limite superior para g(n) • f(n) domina assintoticamente g(n) Exemplo: Dizer que o tempo de execução T(n) de um programa é O(n²), significa que existem constantes c e m tais que, para valores de n ≥ m, T(n) ≤ cn². Exemplo: Provar que g(n) = 3n³ + 2n² + n é O(n³). • Basta mostrar que 3n³ + 2n² + n ≤ 6n³, para n ≥ 0. • A função g(n) = 3n³ + 2n² + n é também O(n 4), entretanto esta afirmação é mais fraca do que dizer que g(n) é O(n³). Notação Ômega ( Ω ) Esta notação é utilizada para analisar o melhor caso. Uma função f(n) = Ω(g(n)) (lê-se f(n) está em g(n)) se existem constantes c e n0 tal que c.g(n) <= f(n) para n >= n0. Deve ficar claro que, Ω é “inversa” de O, ou seja, uma função F está em (G) se e somente se G está em O(F). Isso significa que: • f(n) é um limite inferior para g(n) Exemplo: Para mostrar que g(n) = 3n³ + 2n² é Ω(n³) basta fazer c = 1, e então 3n³ + 2n² ≥ n³ para n ≥ 0. Para todos os valores à direita de n0, o valor de f(n) está sobre ou acima do valor de cg(n). Notação Theta ( Θ ) Esta notação é utilizada para analisar o caso médio. Uma função f(n) = Θ(g(n)) (lê-se f(n) está em g(n)) se existem constantes c1, c2 e n0 tais que c1. g(n) <= f(n) <= c2.g(n) para n >= n0. Dizemos que neste caso, g(n) é um limite assintótico firme. Exemplo: Seja g(n) = n²/3 − 2n, mostre que g(n) = Θ(n²). • Temos de obter constantes c1 , c2 e m tais que c1n² ≤ 1/3n² − 2n ≤ c2n2 para todo n ≥ m. • Dividindo por n² leva a c1 ≤ 1/3 − 2/n ≤ c2. • O lado direito da desigualdade será sempre válido para qualquer valor de n ≥ 1 quando escolhemos c2 ≥ 1/3. • Escolhendo c1 ≤ 1/21, o lado esquerdo da desigualdade será válido para qualquer valor de n ≥ 7. • Logo, escolhendo c1 = 1/21, c2 = 1/3 e m = 7, verifica-se que n2/3 − 2n = Θ(n²). Outras constantes podem existir, mas o importante é que existe alguma escolha para as três constantes.