capítulo 11 - ordem de grandeza do crescimento assimptótico:...

32
387 Capítulo 11 - Ordem de grandeza do crescimento assimptótico: principais notações Neste capítulo abordaremos, muito sucintamente, o crescimento assimptótico de funções, motivando o interesse em estudar a ordem de grandeza da rapidez do crescimento de funções que ocorrem em certos contextos (e nomeadamente no contexto da análise da eficiência de algoritmos e da complexidade de problemas), e introduzindo as principais notações usadas para caracterizar tal ordem de grandeza. Secção 1: Motivação (computabilidade, complexidade e eficiência). Face a um problema (ou uma tarefa), temos, à partida, duas questões: i) saber se ele (ela) é resolúvel; ii) e, em caso afirmativo, determinar uma solução, resolvendo-o (realizando a tarefa em causa) 1 . Pensemos agora em problemas (ou tarefas), como os ilustrados p.ex. na secção 2 do capítulo 9, que dependem de certas grandezas, que podemos classificar de parâmetros do problema. Suponha-se para simplificar que se trata de um problema/tarefa, que designaremos genericamente de T, que depende apenas de um parâmetro, que designaremos a seguir genericamente de n. Para cada valor de n, temos então um problema/tarefa específico (que podemos designar de T(n)) que se pode dizer que é uma instância desse problema/tarefa genérico T. Por exemplo, a tarefa dos monges das Torres de Hanoi é uma instância da tarefa genérica de “mover n discos (sem violar a restrição em causa)”, em que o número n de discos é igual a 64; assim como a tarefa/problema de ordenar a lista {8,-9,25,4} é uma instância da tarefa ou problema genérico de “ordenar uma lista de números”. Embora um problema (desse tipo) possa, à partida, ser solúvel para certos valores de n e insolúvel para outros valores de n, quando dizemos “sem mais nada” que um tal problema é solúvel, pretendemos dizer que ele é solúvel para todos os valores de n, i.e. para todas as suas instâncias. (No que se segue podemos supor que a solução de cada instância, quando existe, é única.) E, informalmente, dizemos que um problema (uma tarefa) T é computável (ou solúvel computacionalmente) se ele não só é solúvel, como a sua solução é computável, no sentido de que existe algum programa P (codificável nalguma hipotética linguagem de programação), que recebendo como input n retorna a solução 2 dessa instância T(n) (realiza a tarefa T(n)). 1 Não é nossa intenção distinguir problema e tarefa. Estamos aqui a usar os dois termos de uma forma perfeitamente informal que pretende apenas sugerir que estamos a pensar genericamente de “problemas” cuja resolução pode exigir quer a realização de acções físicas (normalmente associadas às tarefas, embora também se possa falar de “tarefas mentais”), quer a realização de acções de natureza mental, de cálculo ou outro carácter formal (como normalmente associamos a “problemas matemáticos”). De qualquer forma, quando elas são realizadas em computador (em realidade virtual), nada distingue as duas realizações, ambas se traduzindo na execução de um conjunto de operações disponibilizadas pela linguagem de programação utilizada. 2 Se se tratar p.ex. de um problema T de natureza numérica, podemos dizer que T é computável se a hipotética função g que para cada valor do parâmetro n nos dá a solução de T(n) é computável, no sentido de que existe algum programa P que recebendo como input n retorna o valor de g(n).

Upload: nguyenthuan

Post on 20-Nov-2018

216 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

387

Capítulo 11 - Ordem de grandeza do crescimento assimptótico: principais notações

Neste capítulo abordaremos, muito sucintamente, o crescimento assimptótico de funções, motivando o

interesse em estudar a ordem de grandeza da rapidez do crescimento de funções que ocorrem em certos

contextos (e nomeadamente no contexto da análise da eficiência de algoritmos e da complexidade de

problemas), e introduzindo as principais notações usadas para caracterizar tal ordem de grandeza.

Secção 1: Motivação (computabilidade, complexidade e eficiência).

Face a um problema (ou uma tarefa), temos, à partida, duas questões: i) saber se ele (ela) é resolúvel; ii) e,

em caso afirmativo, determinar uma solução, resolvendo-o (realizando a tarefa em causa)1.

Pensemos agora em problemas (ou tarefas), como os ilustrados p.ex. na secção 2 do capítulo 9, que

dependem de certas grandezas, que podemos classificar de parâmetros do problema. Suponha-se para

simplificar que se trata de um problema/tarefa, que designaremos genericamente de T, que depende apenas

de um parâmetro, que designaremos a seguir genericamente de n. Para cada valor de n, temos então um

problema/tarefa específico (que podemos designar de T(n)) que se pode dizer que é uma instância desse

problema/tarefa genérico T.

Por exemplo, a tarefa dos monges das Torres de Hanoi é uma instância da tarefa genérica de “mover n

discos (sem violar a restrição em causa)”, em que o número n de discos é igual a 64; assim como a

tarefa/problema de ordenar a lista {8,-9,25,4} é uma instância da tarefa ou problema genérico de

“ordenar uma lista de números”.

Embora um problema (desse tipo) possa, à partida, ser solúvel para certos valores de n e insolúvel para

outros valores de n, quando dizemos “sem mais nada” que um tal problema é solúvel, pretendemos dizer

que ele é solúvel para todos os valores de n, i.e. para todas as suas instâncias. (No que se segue podemos

supor que a solução de cada instância, quando existe, é única.)

E, informalmente, dizemos que um problema (uma tarefa) T é computável (ou solúvel

computacionalmente) se ele não só é solúvel, como a sua solução é computável, no sentido de que existe

algum programa P (codificável nalguma hipotética linguagem de programação), que recebendo como input

n retorna a solução2 dessa instância T(n) (realiza a tarefa T(n)).

1 Não é nossa intenção distinguir problema e tarefa. Estamos aqui a usar os dois termos de uma forma perfeitamente informalque pretende apenas sugerir que estamos a pensar genericamente de “problemas” cuja resolução pode exigir quer a realizaçãode acções físicas (normalmente associadas às tarefas, embora também se possa falar de “tarefas mentais”), quer a realizaçãode acções de natureza mental, de cálculo ou outro carácter formal (como normalmente associamos a “problemasmatemáticos”). De qualquer forma, quando elas são realizadas em computador (em realidade virtual), nada distingue as duasrealizações, ambas se traduzindo na execução de um conjunto de operações disponibilizadas pela linguagem de programaçãoutilizada.2 Se se tratar p.ex. de um problema T de natureza numérica, podemos dizer que T é computável se a hipotética função g quepara cada valor do parâmetro n nos dá a solução de T(n) é computável, no sentido de que existe algum programa P querecebendo como input n retorna o valor de g(n).

Page 2: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

388

No âmbito da teoria da computabilidade3, temos um problema e queremos saber se ele é solúvel

computacionalmente. Para esse fim, qualquer programa que resolva o problema serve, e quanto mais

simples for melhor. Aliás, para esse fim basta-nos mostrar que é possível construir tal programa, não se

tornando necessário construí-lo mesmo.

Naturalmente, isso na prática não nos chega, se queremos mesmo resolver um problema (ou realizar

uma tarefa) computacionalmente (e não, apenas, saber se teoricamente é resolúvel computacionalmente).

Nesse caso, temos de construir um programa que resolva o problema (realize a tarefa).

Mas tal ainda não nos basta.

Precisamos de "ter uma ideia" (uma medida) do seu tempo de execução, e saber se tal tempo é exequível

na prática4. A questão é como o determinar.

Repare-se que pôr o programa a correr, num determinado computador, para certas instâncias do

problema (para certos valores do parâmetro n) não é uma boa estratégia. Suponha-se p.ex. que pomos o

programa (que resolve em realidade virtual o problema) das Torres de Hanoi a correr para uma instância

pequena do problema (p.ex. com n=3): o programa correrá rapidamente. Mas se pusermos a correr o

mesmo programa para a instância original com 64 discos (ou para uma com 128 discos), e resolvermos

esperar para ver quanto tempo demora: bem poderemos esperar5 ...

Assim, o que precisamos é de traduzir tal tempo de execução como uma função matemática do seu

parâmetro n e estudar como ela se comporta.

Como calcular esse tempo de execução ?

O que se pretende não é que tal função nos dê, para cada valor de n, o tempo exacto que demora a correr

o programa (com esse input n ) num dado computador, pois esse tempo varia de computador para

computador. Uma hipótese consiste em associar a cada tipo de operação executada pelo programa um certo

parâmetro que denota o tempo de execução dessa operação6, contar o número de vezes que são efectuadas

cada uma dessas operações, e a partir daí calcular o tempo total de execução do programa como uma função

do input n, parametrizada a esses tempos (tempos que depois podemos, naturalmente, instanciar).

No entanto, a análise anterior, em que se entra em linha de conta com todas as operações executadas

pelo programa, pode-se mostrar (desnecessariamente) bastante complexa. O que é essencial obter é um

valor que traduza de algum modo o custo da execução do programa, para cada input n. E, para esse efeito,

muitas vezes basta-nos contar o número de vezes que são efectuadas as principais operações que são

realizadas pelo programa em causa (e depois, se tal for desejado, podemos associar um tempo a cada uma

dessas operações, obtendo uma ideia aproximada do tempo de execução em causa).

3 Sucintamente, podemos dizer que a teoria da computabilidade procura caracterizar as funções que são computáveis. Refira-se, a propósito, que embora a generalidade das funções naturais de variáveis naturais com que nos deparamos sejam (pelomenos teoricamente) computáveis, existem (é possível conceber) funções que o não são.4 O tempo de execução não é o único aspecto relevante na análise de um programa. Este consome outros recursoscomputacionais, como memória, que também têm de estar disponíveis. Mas, em geral concentramos a nossa análise no tempo deexecução.5 E se resolvermos desistir de esperar, ao fim de quanto tempo devemos tomar essa decisão?6 Tempo esse cujo valor concreto depende do sistema computacional em que tal programa é implementado.

Page 3: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

389

Por exemplo, no caso das Torres de Hanoi podemos dizer que o que traduz o custo da execução do

programa é o número mínimo de movimentos de discos que é necessário realizar. E, no caso dos

programas de ordenação, podemos supor que o seu custo é essencialmente determinado pelo número de

comparações de elementos que são necessárias para ordenar a lista em causa7.

De posse de uma tal função de custo do programa (que a seguir designaremos genericamente de) f,

podemos então estudar como se comporta o custo/tempo de execução do programa em função do valor n do

seu input. Mas, se só pretendemos saber até que ponto a escolha de um tal programa é exequível na

prática, então o valor de f(n), para pequenos valores de n, não é relevante. De facto, se assumirmos que o

nosso parâmetro n traduz uma medida da dimensão (ou complexidade) da instância do problema a resolver,

é fácil de constatar que o custo da execução dos programas para n pequeno não é muito relevante: com as

actuais computadores, mesmo um “mau8 programa” resolverá muito rapidamente uma pequena instância

do problema. O que é fundamental é saber o custo/tempo da execução para instâncias grandes, ou mesmo

muito grandes: e tal leva-nos ao interesse do estudo do comportamento assimptótico de tais funções

(podemos mesmo dizer ao estudo do seu crescimento assimptótico, uma vez que tais funções serão

naturalmente crescentes: podemos asumir que como regra o custo da solução cresce com o crescimento da

dimensão da instância a resolver).

Mais ainda, para esses efeitos, pode não ser fundamental conhecer a expressão explícita exacta de f(n),

como função de n, a qual em certos casos pode não ser fácil de obter (mesmo só considerando as operações

essenciais do programa). De facto, embora para valores pequenos de n, a expressão exacta de f(n) seja

relevante, como acabámos de referir, esses casos não são fundamentais para o fim indicado. E, quando

pensamos em valores grandes de n (que traduzem os casos mais demorados de resolver), o valor exacto de

f(n) já não é tão relevante. O essencial é conhecer a sua ordem de grandeza (ou ordem de crescimento - ”rate

of growth”), para o que nos procuramos libertar do máximo de detalhes possível. Por exemplo, se tal

função de custo for majorada por um polinómio em n, de grau k, sabemos que no pior caso terá um

comportamento polinomial de grau k.

Assim o que se procura estudar é, fundamentalmente, o comportamento assimptótico de tais funções de

custo e saber, por exemplo, se o tempo de execução do programa é uma função polinomial de n, e de que

ordem de grandeza, ou se cresce exponencialmente. Programas cujo custo cresça exponencialmente como

função de n não têm qualquer interesse prático, salvo eventualmente para valores muito pequenos de n, e

podemos considerar, informalmente, que um problema é intratável se qualquer9 solução computacional

para ele é dessa ordem de grandeza.

7 Considerando que as comparações de elementos são as operações básicas, ou essenciais, que estão por detrás dofuncionamento dos algoritmos de ordenação. De facto, para além destas, ainda poderemos ter de entrar em consideração com osmovimentos de elementos da lista, mas não pretendemos entrar agora nesses “detalhes”.8 Mau, no sentido de pouco eficiente (pouco rápido). Será sempre essencial que seja um programa que resolva o problema !9 Naturalmente, um problema não é intratável só porque um determinado programa que o resolve tem um tempo de execuçãoexponencial. Pode ser que seja o algoritmo em causa que seja mau e que possa ser possível construir programas que resolvam oproblema em tempo polinomial.

Page 4: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

390

Os algoritmos10 podem ser divididos em duas grandes classes: os com uma ordem de grandeza

polinomial, limitada superiormente por uma potência de n (nα, com α≥0), e os com uma ordem de

grandeza exponencial, limitada inferiormente por uma exponencial (cn, com c>1). Um problema para o

qual existe algum algoritmo que na pior situação se comporta polinomialmente é considerado

“tratável”/aceitável11: a classe desses problemas é designada de P. Os problemas para os quais qualquer

algoritmo na pior situação se comporta exponencialmente é considerado intratável. Existe uma classe

grande de problemas que se sabe serem solúveis computacionalmente, para os quais se sabe existirem

soluções exponenciais, e que se suspeita serem intratáveis, embora tal não se tenha ainda conseguido

provar: a classe desses problemas é designada de NP. O estudo deste tópico é objecto da chamada teoria da

complexidade.

Considere-se agora que temos um problema concreto que queremos resolver computacionalmente, e

que, em particular, tal tipo de problema ocorre frequentemente em várias aplicações (p.ex. ordenação de

listas). Então nós não só queremos construir um programa que o “resolva em tempo útil”, como queremos

encontrar programas que sejam o mais eficientes possíveis para resolver aquele tipo de problema12. (Em

particular, nesses casos já não é verdade que quanto mais simples for o programa melhor13.)

Suponha-se, por exemplo, que dispomos de dois (ou mais) programas que resolvem o problema em

causa e queremos escolher o “melhor” (no sentido de o mais eficiente – com menor tempo/custo de

execução) de entre eles.

Embora se possa proceder a uma análise empírica (pondo os dois programas a correr, para várias

instâncias do problema, e comparando os seus tempos de execução num dado computador), como

justificaremos no próximo capítulo, a informação que obtemos de tal análise empírica é limitada (e em

alguns casos poderá ser enganadora).

Nesse caso, há que proceder a uma análise (tão exaustiva quanto possível) dos programas, estudando

p.ex. como o comportamento destes é afectado por certas características dos input’s. Uns programas

poderão ser melhores para instâncias do problema com certas características, e piores para instâncias com

outras características e, a partir dessa análise, em função do tipo de instância em questão, podemos optar

por um programa ou por outro.

10 Não iremos neste texto debruçarnos em pormenor sobre a diferença entre algoritmo e programa. Informalmente, quandofalamos num algoritmo para a solução de um determinado problema estamos a pensar na descrição apenas dos aspectosessenciais da construção de uma determinada solução desse problema. Como estamos a falar de soluções computacionais, oalgoritmo terá de estar descrito numa linguagem que contemple as usuais formas de construção de programas, i.e., de algummodo, numa linguagem de programação. Mas tal linguagem de programação poderá ser de muito alto nível, e eventualmenteabstracta. Assim, um algoritmo não tem de estar escrito numa linguagem de programação real, concreta, o que permite que nasua descrição não tenhamos de estar dependentes de (eventuais) detalhes muito específicos dessas linguagens, e nos possamosconcentrar na descrição apenas do que é a essência do programa.11 De qualquer forma, como mostraremos à frente, um algoritmo com uma ordem de grandeza polinomial nα, também só teminteresse na prática para α<2, salvo se os valores de n não forem muito grandes.12 Para problemas que ocorrem muito frequentemente, tais programas já estarão com certeza estudados, mas não é esse oaspecto que nos interessa agora.13 Embora, para programas de eficiência análoga, a simplicidade não deixe de ser um critério de escolha, até por ser maissimples de evitar (e detectar) eventuais erros em programas mais simples do que em programas mais complexos.

Page 5: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

391

E, mais uma vez, o que se procura fazer é construir, estudar e comparar a função de custo de cada um

dos programas.

Refira-se, a propósito, que nem sempre se considera que o parâmetro dessa função é o input concreto do

programa. Muitas vezes o que se considera como parâmetro da função de custo da execução do programa é

um valor que traduz apenas a complexidade (ou dimensão) desse input14.

Suponha-se, por exemplo, que se pretende analisar o custo de execução de um programa para a

ordenação de listas. Ora, o tempo que um determinado programa demora a ordenar uma lista (que recebe

como input), depende fortemente da lista concreta em causa (do número de elementos fora de ordem, de

como estes se dispõem, etc.). Assim, a caracterização matemática da função de custo de tal programa,

como uma função da lista a ordenar, seria extremamente complicada15. Deste modo, quando se aborda o

problema da ordenação de listas, o parâmetro da função de custo é em geral o comprimento da lista a

ordenar e não a lista concreta a ordenar. Mas, naturalmente, só sabendo a dimensão da lista a ordenar, não

conseguimos determinar o custo exacto da sua ordenação (pois, como referimos, tal depende da composição

dessa lista). Assim, o que se faz, é estudar o custo da ordenação, em função do comprimento n da lista a

ordenar, considerando: a pior situação (i.e. a situação em que o input, de dimensão n, tem as piores

caraterísticas para o programa em causa), a melhor situação e em média (não assumindo nada sobre o input

em causa, i.e. considerando que ele pode ser um qualquer input de dimensão n, e supondo que todos estes

input’s são igualmente prováveis)16. Este tipo de análise será ilustrada no próximo capítulo.

De qualquer forma, para a comparação das funções de custo de dois programas (que resolvem o mesmo

problema), com vista a decidir qual é o melhor17, continua a não ser fundamental saber qual o valor de tais

funções para valores pequenos de n. Como já observámos, para pequenas instâncias do problema, nos

14 Por outro lado, embora, para simplificar, estejamos a assumir aqui que a função de custo de execução de um programa sódepende de um valor (de um parâmetro), em alguns casos é melhor traduzir a dimensão do input através de mais do que umnúmero. Por exemplo, para certos algoritmos sobre grafos (em que o input é um grafo), uma maneira de descrever a dimensãodo input poderá ser através da referência ao número de vértices e ao número de setas do grafo, e para programas que operamsobre matrizes, a dimensão destas será em geral traduzida pelos números de linhas e de colunas que as compõem.15 Além de pouco útil, por demasiado pormenorizada.16 Frequentemente, os algoritmos são comparados em função da ordem de grandeza do seu custo, no pior caso. No entanto, naprática nem sempre algoritmos com uma má ordem de grandeza no pior caso são de excluir. Pode acontecer, e muitas vezesacontece, que a pior situação seja pouco provável (raramente ocorra) na aplicação em causa. Assim, é importante fazertambém uma análise da ordem de grandeza do custo do algoritmo em média, assumindo que qualquer input de dimensão n éequiprovável (análise normalmente mais complicada que a análise no pior caso). Por outro lado, embora a análise da melhorsituação para um dado algoritmo seja menos relevante, ela permite que face a uma dada aplicação, se os input’s esperados estãoem geral próximos da situação óptima do algoritmo, este possa ser escolhido, mesmo que no pior caso, ou em média, seja um maualgoritmo. Por exemplo (ver próximo capítulo), o algoritmo da inserção directa é em média um mau algoritmo de ordenação, masé o (ou dos) melhor(es) quando há poucos elementos fora de ordem; assim, numa aplicação em que os dados são em princípioguardados numa tabela por ordem, mas em que por alguma razão um ou outro dado pode ter sido inserido fora de ordem, podejustificar-se fazer uma ordenação da tabela pelo método da inserção directa (para garantir que esta fica mesmo ordenada esuporta portanto, por exemplo, uma pesquisa binária de um elemento).17 Muitas vezes não se pode dizer que um é o melhor. Como já referimos, um pode ser melhor p.ex. para instâncias com certascaraterísticas, e o outro pode ser melhor para outro tipo de instâncias.

Page 6: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

392

actuais computadores, qualquer programa que “se preze” as resolverá muito rapidamente18. O que é

fundamental é ter uma ordem de grandeza do custo da execução dos programas para input’s de grande (ou

mesmo muito grande) dimensão.

No próximo capítulo ilustraremos como construir tais funções de custo (ou de complexidade) para

certos algoritmos. Neste capítulo iremos debruçar-nos sobre a caracterização assimptótica de funções desse

tipo e introduzir as principais notações que são usadas para descrever a ordem de grandeza do seu

crescimento assimptótico.

Para terminar esta secção introdutória, caracterizemos apenas o tipo de funções em cuja análise estamos

interessados.

Em primeiro lugar, embora o custo de execução de um determinado programa possa depender de mais

do que uma quantidade (por exemplo, em alguns casos de programas com mais do que um argumento),

iremos em seguida concentrar-nos no caso mais simples, e mais importante, em que esse custo depende

apenas de um argumento natural. Por outro lado, se f(n) traduz o custo de execução de um algoritmo, para

um dado input n, surge natural supor que f(n) é um número real positivo, ou pelo menos19 não negativo e

positivo a partir de uma certa ordem20.

Assim, no que se segue iremos assumir que as funções em consideração são sempre (salvo referência

em contrário) aplicações de |N0 em |R, que são não negativas e positivas a partir de uma certa ordem.Por outro lado, como se assume que o argumento da função traduz a dimensão (ou complexidade) do

input do algoritmo, na generalidade dos casos as funções de custo em consideração serão crescentes (pelo

menos em sentido lato21), crescendo (mesmo) para infinito à medida que n tende para infinito.

Secção 2: Comparação das ordens de crescimento assimptótico e principais notações.

Comecemos por sintetizar o que de essencial (para o que se segue) se observou na secção anterior.

Suponha-se que f(n) traduz, de alguma forma, o custo da execução de um certo algoritmo, em função de

um certo natural n, que representa o valor do (de um) parâmetro que afecta mais significativamente o

tempo de execução do algoritmo. O valor de f(n) tanto pode representar tempo (expresso em segundos,

micro-segundos, nano-segundos, ou outra unidade de tempo), como o número total de operações realizadas,

ou o número de operações de certo tipo realizadas (p.ex. número de comparações, no caso dos algoritmos

de ordenação), ou uma outra qualquer medida que traduza a complexidade/tempo de execução do algoritmo.

18 O custo/tempo de execução de um algoritmo, para valores pequenos do seu input, já poderá contudo ser relevante, emcontextos em que tal algoritmo faz parte de um outro algoritmo que o invoca sucessivamente (mesmo que em cada invocação eleseja aplicando a input’s de reduzida dimensão).

19 Muito do que se segue pode generalizar-se a outro tipo de funções, e nomeadamente a funções que podem assumir valoresnegativos: nesse caso, no que se segue considerar-se-ia (nas definições) o módulo dessas funções. De qualquer forma, nãopretendemos abordar este tópico na sua forma mais geral, mas apenas introduzir as ideias essenciais.20 Isto é: ∃p≥0∀n≥p f(n)>0. Tal permite que se possa considerar funções de custo que para certos valores iniciais (como n=0)assumem o valor zero.21 Recorde-se que f: |N0 → |R é crescente em sentido lato sse ∀n,k≥0 (n>k ⇒ f(n)≥f(k)).

Page 7: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

393

É interessante conhecer a expressão explícita exacta de f(n), como função de n. Mas, não só tal pode ser

muitas vezes difícil de obter, como para muitos efeitos pode não ser extraordinariamente relevante. De

facto, embora para valores pequenos de n a expressão exacta de f(n) seja relevante, não são em geral esses

os casos que nos levam a optar por um algoritmo face a outro. Embora face a um problema concreto se

deva procurar escolher sempre o melhor algoritmo que o resolve, se a dimensão n do problema for

pequena, nos computadores actuais, em geral qualquer programa que o resolva, demorará relativamente

pouco tempo. Mas a situação já não é a mesma quando pensamos em valores grandes (suficientemente

grandes22) de n. Daí que ao analisarmos a eficiência de um algoritmo, nos preocupemos essencialmente

com o estudo do comportamento assimptótico23 da função f que traduz o seu custo. E, quando pensamos

em valores grandes de n, o valor exacto de f(n) já não é tão relevante. O essencial é conhecer a sua ordem

de grandeza (ou ordem de crescimento - ”rate of growth”) para o que nos procuramos libertar do máximo de

detalhes possível.

Em resumo, quando queremos escolher entre dois algoritmos para um dado problema, procuramos, em

geral, escolher aquele cuja ordem de crescimento assimptótica é menor. Resta traduzir o que isto significa

exactamente. A tal passamos, de imediato.

Crescimento assimptótico mais lento: “little-Oh notation” e “little-omega notation”

Suponha-se, por exemplo, que dispomos de dois algoritmos para resolver um determinado problema, e

que f(n) e g(n) traduzem os custos da execução de cada um deles (em função de um certo input n). Era bom

que dispuséssemos de critérios que nos permitissem optar, em certas condições, por um dos algoritmos,

mesmo sem conhecer a expressão exacta dessas funções (por exemplo, o valor de certas constantes

eventualmente envolvidas nas expressões em causa).

Será que existe algum critério que nos permita logo optar por um dos algoritmos por o seu custo f(n)

se tornar insignificante relaticamente ao custo g(n) do outro algoritmo, para n suficientemente grande (à

medida que n se aproxima do infinito) ?

Usando

f p g (ou24

f (n) p g(n) ) para traduzir uma situação desse género – que se lê dizendo que a

ordem (de crescimento) de f é menor que a ordem (de crescimento) de g, o que significará dizer que f(n) se

torna insignificante25 relativamente a g(n), para n suficientemente grande ?

22 Dependendo dos problemas, o significado de “suficientemente grande” poderá ser muito grande, ou muito muito grande, ounem por isso (pense-se no problema das Torres de Hanoi e no tempo que demoraria o respectivo programa a correr para n=64).23 No sentido amplo de procura de valores aproximados de f(n) para n suficientemente grande. Neste sentido amplo do termo,usamos em geral o termo assimptótico para significar um valor aproximado que fica cada vez mais perto do valor real à medidaque um certo parâmetro (aqui designado por n) se aproxima de um certo valor limite (aqui +∞).24 Iremos, no que se segue, introduzir várias notações úteis para a descrição/comparação da ordem de crescimento assimptóticode funções. Embora essas notações se apliquem a funções, é muito usual, neste contexto, aplicá-las às expressões que asdefinem, identificando de algum modo uma função com a expressão que a define (o que, apesar de não ser muito correcto,como referimos na observação 2 da secção 1 do capítulo 4, é conveniente em muitas situações, por facilitar as descrições).

Assim, usando p.ex. a notação lambda, escreve-se em geral,

n2 p n3 significando

λn.n2 p λn.n3 .25Recorde-se que estamos a pensar em funções (positivas, ou pelo menos positivas a partir de uma certa ordem, e) que crescemindefinidamente, à medida que o seu argumento n cresce.

Page 8: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

394

A ideia é que o valor de g(n) vai crescer de tal modo face ao valor de f(n), que conseguimos sempre

encontrar uma ordem a partir da qual f(n) se torna menor (ou menor ou igual) do que uma “fracção” do

valor de g(n), qualquer que seja a “fracção” do valor de g(n) que consideremos. Dito de outra forma, e mais

precisamente (uma vez que a ordem em causa dependerá da fracção escolhida, ao contrário do que poderá

transparecer na formulação anterior), para qualquer valor positivo c, por mais pequeno que seja, existe uma

ordem a partir da qual f(n) < c g(n). Isto é,

f p g sse

∀c∈R +∃n0 ∈N0∀n≥n0 (0 ≤) f (n) ≤ cg(n)

Como estamos a assumir que as nossas funções são positivas (ou positivas a partir de uma certa

ordem), podemos passar para quocientes e escrever, de forma equivalente

∀c∈R +∃n0 ∈N0∀n≥n0 (0 ≤)f (n)g(n)

≤ c

o que não é mais do que dizer (pois as funções em causa nunca assumem valores negativos) que

limn→∞

f (n)g(n)

= 0

Quando uma função f satisfaz a condição anterior, também se diz que f é um zero26 de g, ou um little

oh de g.

Definição/Notação 1 (“o-notation”, ou “little-Oh notation”) :

Designa-se por o(g) o conjunto das funções que têm uma ordem de crescimento (assimptótico) inferior à de

g. Mais precisamente:

o(g) = { f :∀c∈R +∃n0 ∈N0∀n≥n0 (0 ≤) f (n) ≤ cg(n)}

E, em vez de escrever f ∈ o(g) , escreve-se f = o(g) que se lê como se segue “f é um little oh de g”, ou “f é

um zero de g”. Refira-se que este sinal de = deve ser interpretado (nesta, e nas restantes notações a

introduzir neste capítulo) como “é “ e não como igual27 (e, em particular, não se deve escrever o(g) = f).

Naturalmente dizer que

limn→∞

f (n)g(n)

= 0 é equivalente28 a afirmar que

limn→∞

g(n)f (n)

= +∞, ie. que

∀L∈R +∃n0 ∈N0∀n≥n0g(n)f (n)

≥ L

o que se pode descrever escrevendo que g=ϖ(f), condição que se lê dizendo “g é um little-omega de f”.

26 A ideia é que, para n suficientemente grande, f(n) é como se fosse zero quando comparado com g(n): f(n) é um infinitesimalde g(n) (f(n) é desprezável face a g(n)).27 Caso contrário, usando as propriedades da igualdade (e nomeadamente a simetria e a transitividade), obter-se-ia quequaisquer duas funções pertencentes a o(g) eram iguais.28 Como estamos a trabalhar com funções não negativas (e positivas, pelo menos a partir de uma certa ordem), não se dá o caso

de

f (n)g(n)

tender para zero por valores positivos e negativos, em cujo caso só se poderia afirmar que

g(n)f (n)

tenderia para +∝.

Page 9: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

395

Isto é, em vez de se escrever que f=o(g) também se pode escrever, com o mesmo significado, que

g=ϖ(f), o que significa que g(n) se torna arbitrariamente grande relativamente a f(n), à medida que n se

aproxima do infinito.

Definição/Notação 2 (“ ϖ -notation”, ou “little-omega notation”) :

Designa-se por ϖ(f) o conjunto das funções que têm uma ordem de crescimento superior à de f:

ϖ ( f ) = {g :∀L∈R +∃n0 ∈N0∀n≥n0

g(n) ≥ Lf (n) (≥ 0)}

Em vez de escrever g ∈ ϖ(f) , escreve-se g=ϖ(f) que se lê como se segue “g é um little-omega de f”.

Definindo então “

f p g sse f = o(g)”, podemos usar esta relação de ordem para estabelecer uma

hierarquia entre estas funções, em que elas são ordenadas em função da rapidez com que crescem para

infinito.

Vejamos alguns exemplos que nos ajudem a compreender melhor o significado de uma função ter uma

ordem de crescimento inferior à de outra, e a interiorizar que isso corresponde ao valor da primeira ser

insignificante quando comparado com o valor da segunda, mas isto quando (e apenas quando) pensamos em

valores suficientemente grandes29 do seu argumento n.

Considere-se, como primeiro exemplo, que f(n) = 1000 n2 e g(n) = n3. Quando n= 1, f(n) é 1000 vezes

maior que g(n). Mas o que se passa à medida que n vai crescendo ?

• quando n= 1, g(n) é 1000 vezes menor que f(n)

• quando n=2, g(n) é 500 vezes menor que f(n)

• ....

• quando n=1000=103, g(n) = n3 = n n2 = 1000 n2 é igual a f(n)

• quando n=1000000=106, g(n) = n3 = n*n2 = 1000 (1000 n2) é 1000 vezes o valor de f(n)

• quando n=109, g(n) = n3 = n*n2 = 106 (1000 n2) é igual a 106 vezes f(n)

• ....

À medida que n se torna suficientemente grande, o valor de g(n) é cada vez maior que o de f(n), e a

diferença entre os dois valores cresce substancialmente à medida que n cresce. Na realidade, à medida que n

se aproxima do infinito, f(n) torna-se insignificante relativamente a g(n).

Esta “insignificância” torna-se mais evidente se assumirmos que f(n) e g(n) correspondem ao número de

operações executadas por dois algoritmos, e traduzimos em tempo essa medida, assumindo um certo tempo

médio por execução de uma operação.

29 Em que o “valor concreto” de ser suficientemente grande depende de caso para caso. Mas para qualquer caso há um valorsuficientemente grande a partir do qual a função f que cresce mais lentamente se torna insignificante face ao valor da outrafunção g (qualquer que seja a constante c, por mais pequena que seja, conseguimos encontrar uma ordem a partir da qual f(n) émenor que cg(n)).

n = 1,00E+02 1,00E+03 1,00E+06 1,00E+09função 10 100 1000 1000000 1000000000

1000n^2 100000 10000000 1000000000 1,00E+15 1,00E+21n^3 1000 1000000 1000000000 1,00E+18 1,00E+27

Expresso em número de operações

Page 10: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

396

Como referimos atrás, podemos hierarquizar estas funções, em função da rapidez com que crescem para

infinito, recorrendo à relação

p . Assim, e a título de exemplo, tem-se30 (onde “1” designa a função

constantemente igual a 1, e δ, ε, c, d e b designam quaisquer constantes tais que 0<δ<ε<1<c<d e b>1):

1p logb (logb (n)) p logb (n) p nδ p nε p n p nc p nd p n logb n p cn p nn

Refira-se que, com excepção da função constantemente igual a 1, todas as funções acabadas de

hierarquizar crescem para infinito à medida que n tende para infinito. Quando procuramos inserir uma nova

função nesta hierarquia, não procuramos determinar se tende para infinito, mas sim quão rápido o faz.

Para vermos a diferença entre o modo como estas funções crescem, podemos comparar os seus

gráficos31. A seguir tem-se o gráfico conjunto de x e log2x, para x entre 0.1 e 10:

Naturalmente, estes gráficos tornam-se difíceis de visualizar para valores grandes de x.

Podemos também, tal como para o primeiro exemplo, procurar traduzir em tempo o valor de algumas

funções como as anteriores, supondo que elas denotam o número de operações executadas por um certo

algoritmo e que cada operação demora (em média) um certo tempo:

30 Algumas das desigualdades a seguir serão deduzidas à frente.31 Embora estejamos a considerar funções de variável natural, para se melhor visualizar os seus gráficos, podemos consideraras suas extensões naturais a funções de variável real.

n = 1,00E+02 1,00E+03 1,00E+06 1,00E+09função 10 100 1000 1000000 1000000000

1000n^2 0,1 segundos 10 segundos 16,7 minutos 31,7 anos 317098 séculosn^3 0,001 segundos 1 segundo 16,7 minutos 317,1 séculos 317097919838 séculos

Valores aproximados expressos em unidades de tempo, supondo que cada operação demora um micro-segundo (10^(-6) segundos)

n = 1,00E+02 1,00E+03 1,00E+06 1,00E+09função 10 100 1000 1000000 1000000000

1000n^2 quase instantânea 0,01 segundos 1 segundo 277,8 horas 317,1 séculosn^3 quase instantânea 0,001 segundos 1 segundo 31,71 anos 317097919 séculos

Valores aproximados expressos em unidades de tempo, supondo que cada operação demora um nano-segundo (10^(-9) segundos)

Page 11: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

397

As últimas três linhas da tabela anterior ilustram bem a diferença entre o comportamento polinomial e

o exponencial: como se vê nas duas últimas linhas32, o crescimento exponencial a partir de certa altura

“explode” autenticamente.

Se conseguirmos determinar p.ex. que a função de custo f(n), de um certo algoritmo, é um polinómio,

e que a função de custo g(n) de um outro algoritmo, para o mesmo problema, é uma exponencial cn, com

c>1, então, mesmo que não conheçamos os coeficientes do polinómio f(n), devemos escolher o primeiro

algoritmo, pois ter-se-á sempre que f = o(g).

Podemos ainda ter uma ideia da rapidez do crescimento das várias funções, analisando o efeito de

duplicar o seu argumento A próxima tabela mostra-nos esse efeito para algumas funções comuns, listadas

na hierarquia atrás referida (mais precisamente, na tabela a seguir a segunda coluna diz-nos como se

relaciona f(2n) com f(n): p.ex. factor 4 significa que f(2n) é o quádruplo de f(n), i.e. f(2n) = 4 f(n)):

função f(n): efeito de duplicar o argumento

1 nenhum

lg n (i.e. log2n) ligeiro acréscimo

n duplica

n lgn um pouco mais que o dobro

n3/2 factor

2 2

n2 factor 4

n3 factor 8

2n quadrado

32 Na ferramenta computacional usada para gerar as tabelas acima (o Excel) já não foi possível calcular os valores de 1,110000

e de 1,11000000. Embora o cálculo desses valores não seja essencial para o que se pretende ilustrar, refira-se que (usando p.ex. oMathematica se pode obter) 1,110000 = 8,44990025120603 x 104 1 3 e 1,11000000 = 4,8434879665682 x 1041392.

Lg = log na base 2 n = 1,00E+02 1,00E+03 1,00E+04 1,00E+06função 10 100 1000 10000 1000000Lg n 3,32 6,64 9,97 13,29 19,93

n^0.5 3,16 10,00 31,62 100,00 1000,00n 10,00 100,00 1,00E+03 1,00E+04 1,00E+06

n Lg n 33,22 664,39 9,97E+03 1,33E+05 1,99E+07n^1.5 31,62 1000,00 3,16E+04 1,00E+06 1,00E+09n^2 100,00 10000,00 1,00E+06 1,00E+08 1,00E+12

1,01^n 1,1 2,7 2,10E+04 1,64E+43 #NUM!1,1^n 2,6 13780,6 2,47E+41 #NUM! #NUM!

Expresso em número de operações o Excel já não calcula estes valores

Lg = log na base 2 n = 1,00E+02 1,00E+03 1,00E+04 1,00E+06função 10 100 1000 10000 1000000

Lg n 0,0000033 segundos0,000007 segundos 0,000010 segundos 0,000013 segundos 0,00002 segundosn^0.5 0,0000032 segundos0,00001 segundos 0,00003 segundos 0,0001 segundos 0,001 segundos

n 0,00001 segundos 0,0001 segundos 0,001 segundos 0,01 segundos 1 segundon Lg n 0,000033 segundos 0,0006 segundos 0,00997 segundos 0,13 segundos 19,9 segundosn^1.5 0,000032 segundos 0,001 segundos 0,032 segundos 1 segundo 16,7 minutosn^2 0,0001 segundos 0,01 segundos 1 segundo 1,7 minutos 11,57 dias

1,01^n 0,0000011 segundos0,000003 segundos 0,02 segundos 5,19E+27 séculos1,1^n 0,0000026 segundos0,014 segundos 7,83E+25 séculos

Valores aproximados expressos em unidades de tempo, supondo que cada operação demora um micro-segundo (10^(-6) segundos)

Page 12: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

398

Crescimento assimptótico da mesma ordem de grandeza: “big theta notation”

Tendo definido quando é que a ordem de crescimento de uma função é menor do que a de outra função,

surge natural que nos questionemos sobre quando é que podemos dizer que duas funções crescem da mesma

forma para infinito33 (têm a mesma ordem de crescimento).

Assumindo que os limites que se seguem existem, uma primeira definição natural seria dizer que f(n) e

g(n) têm a mesma ordem de grandeza (crescem com a mesma rapidez para infinito), o que poderemos

denotar escrevendo f(n) ~ g(n), sse

limn→∞

f (n)g(n)

= 1

De acordo com esta definição, dois polinómios

p(n) = aini

i= 0

d

∑ (com34 ad>0) e

q(n) = bini

i= 0

c

∑ (com bc>0)

têm a mesma ordem de grandeza assimptótica sse têm o mesmo grau (d=c) e o coeficiente do termo de

maior grau é o mesmo (ad = bc).

Por exemplo, n2+1000n ~ n2. Veja-se a diferença entre os valores em causa, à medida que n cresce

(onde f(n)= n2+1000n e g(n)=n2):

• quando n=1, tem-se f(1) = 1001 e g(1) = 1, pelo que f(1) é mais de mil vezes maior que g(1)

• e, à medida que n cresce, f(n) continua a ser sempre maior do que g(n), mas a diferença entre os dois

valores (dada por 1000n) torna-se insignificante face ao valor em causa, como é imediato de verificar

quando vemos a evolução do quociente

f (n)g(n)

=n2 +1000n

n2= 1+

1000n

que é igual a:

• 2, quando n = 1000 = 103

• 1,001, quando n = 1000 = 106

• 1,000001, quando n = 109

• ...

À medida que n se torna suficientemente grande, têm claramente a mesma ordem de grandeza.

Observação 1 (utilização da “o-notation” numa expressão) :

Como referimos atrás o(g) designa não uma função, mas o conjunto de funções:

o(g) = { f :∀c∈R +∃n0 ∈N0∀n≥n0 f (n) ≤ cg(n)}

e, como também referimos, em vez de se escrever f ∈ o(g) , escreve-se f = o(g).

33 Dadas duas funções que crescem para infinito, nem sempre se está perante uma situação em que uma delas cresce maisdepressa do que a outra. Não só elas poderão crescer com a mesma rapidez, como poderão existir mesmo casos em que nãoconseguimos comparar a ordem de grandeza do seu crescimento (de acordo com as definições dadas).34 Tal garante que o polinómio é assimptoticamente positivo. Mas, como estamos só a considerar funções não negatrivas,podemos supor que (para além disso) todos os coeficientes ai são maiores ou iguais a zero.

Page 13: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

399

Por outro lado, pode também utilizar-se a “notação o” numa expressão, como por exemplo n3+o(n2).

Neste caso, o(n2) deve ser interpretado como designando uma função (anónima), não completamente

especificada, mas que se sabe que pertence ao conjunto o(n2) (e diferentes ocorrências de o(n2) numa mesma

expressão designarão funções desse conjunto, não necessariamente iguais).

E podemos escrever “equações” em que um (ou mais) o(g) ocorrem na expressão do lado direito, as

quais são (assim) interpretadas como significando que existe alguma função desse conjunto para a qual a

equação em causa é verdadeira: por exemplo, a equação 2n3+3n+1000 = 2n3+o(n2) significará que existe

uma função f ∈ o(n2), tal que 2n3+3n+1000 = 2n3+f(n) (no caso a função f(n) = 3n+1000).

Usando esta interpretação, podemos escrever

f(n) ~ g(n) ⇔ f(n) = g(n) + o(g(n))

como é fácil de verificar:

⇒: f(n) = g(n)+(f(n)-g(n)) e

limn→∞

f (n)g(n)

= 1⇒ limn→∞

f (n) − g(n)g(n)

= 0

⇐: se f(n) = g(n)+h(n) com h(n) ∈ o(g(n)), então:

limn→∞

f (n)g(n)

= limn→∞

g(n) + h(n)g(n)

= 1+ 0 = 0

As observações efectuadas sobre o significado da ocorrência da notação o numa expressão e numa

equação são válidas também para as notações a introduzir a seguir.

Considere-se agora as seguintes funções: f(n) = 5n2 e g(n) = n2. Não se tem f(n) ~ g(n), uma vez que

limn→∞

f (n)g(n)

= 5≠ 1

Neste caso concreto, f(n) é igual a 5 vezes o valor de g(n), seja qual for o valor de n. Mas, como estamos a

pensar em grandes números, talvez o facto de f(n) ser 5 vezes o valor de g(n) não justifique dizer que f(n) e

g(n) têm diferentes ordens de crescimento.

Compare-se o crescimento de algumas funções (para ser mais simples a comparação, limitar-nos-emos

a seguir a funções polinomiais):

Apesar de haver uma diferença relevante entre os valores de 1000n2 e n2 (o peso dos termos de menor grau

é claramente irrelevante, para n grande: compare-se p.ex. n2 e n2+5000n), à medida que n cresce podem-se

notar agrupamentos distintos em função do grau do polinómio: por exemplo, para n=106, assumindo que o

valor da função denota o número de operações executadas por um certo algoritmo e que cada operação

n = 1,00E+03 1,00E+06 1,00E+09 1,00E+12 1,00E+24função 100 1000 1000000 1000000000 1000000000000 10000000000000000000000001000n 100000 1000000 1,00E+09 1,00E+12 1,00E+15 1,00E+27

n^2 10000 1000000 1,00E+12 1,00E+18 1,00E+24 1,00E+48n^2+5000n 510000 6000000 1,01E+12 1,00E+18 1,00E+24 1,00E+485n^2+500n 100000 5500000 5,00E+12 5,00E+18 5,00E+24 5,00E+481000n^2 10000000 1000000000 1,00E+15 1,00E+21 1,00E+27 1,00E+51

n^3 1000000 1000000000 1,00E+18 1,00E+27 1,00E+36 1,00E+72n^3+2000n^2 21000000 3000000000 1,00E+18 1,00E+27 1,00E+36 1,00E+72

Expresso em número de operações

n = 1,00E+03 1,00E+06 1,00E+09 1,00E+12 1,00E+24função 100 1000 1000000 1000000000 1000000000000 10000000000000000000000001000n 0,0001 segundos 0,001 segundos 1 segundo 16,7 minutos 11,57 dias 3,17E+08 séculos

n^2 0,00001 segundos 0,001 segundos 16,7 minutos 31,7 anos 3,17E+05 séculos 3,17E+29 séculosn^2+5000n 0,0005 segundos 0,006 segundos 16,8 minutos 31,7 anos 3,17E+05 séculos 3,17E+29 séculos5n^2+500n 0,0001 segundos 0,0055 segundos 1,39 horas 158,6 anos 1,59E+06 séculos 1,59E+30 séculos1000n^2 0,01 segundos 1 segundo 277,8 horas 317,1 séculos 3,17E+08 séculos 3,17E+32 séculos

n^3 0,001 segundos 1 segundo 31,71 anos 317097919 séculos 3,17E+17 séculos 3,17E+53 séculosn^3+2000n^2 0,021 segundos 3 segundos 31,77 anos 317098554 séculos 3,17E+17 séculos 3,17E+53 séculos

Valores aproximados expressos em unidades de tempo, supondo que cada operação demora um nano-segundo (10^(-9) segundos)

Page 14: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

400

demora (em média) um nano-segundo (10-9 segundos), então o crescimento descrito por 1000n demora

cerca de 1 segundo, os crescimentos dados pelos polinómios na tabela em n2 demoram entre 16 minutos e

278 horas, ao passo que os crescimentos dados pelos polinómios na tabela em n3 demoram perto de 32

anos.

Concretizando um pouco, comparemos, por exemplo, os crescimentos das funções 1000n2, n2 e n3.

Quando n=1, 1000n2 = 1000 e n2 = 1, pelo que 1000n2 parece ser muito maior que n2, e à medida que n

cresce 1000n2 continua a ser maior do que n2, mas é maior por um factor constante (1000) que não depende

de n.

E o que se passa com n3? Quando n=1, tem-se n3 = 1, pelo que n3 tem o mesmo valor que n2 e é mil

vezes menor que o valor de 1000n2. Mas n3 = n*n2, pelo que o quociente entre os dois valores (igual a n)

se vai alargando à medida que n cresce. E um fenómeno análogo se passa quando comparamos n3 com o

1000n2; o coeficiente 1000 só “adia” o “momento” (o valor de n) a partir do qual n3 começa a ser maior

que 1000n2: a partir de n=1000, o valor de n3 passa a ser maior que o de 1000n2 e por um factor (

n1000

) que

cresce à medida que n cresce.

É um facto que existe uma diferença, não desprezável, entre o valor de 1000n2 e o de n2: seja qual for o

valor de n, o valor da primeira é 1000 vezes superior ao valor da segunda. E, de acordo com a definição

dada acima, as funções dadas por 1000n2 e n2 não crescem para infinito com a mesma ordem de grandeza

(

1000n2 / ~ n2).

Mas, como vimos, existe uma diferença significativa entre os crescimentos de 1000n2, n2 e n3.

Enquanto a primeira é superior à segunda por um factor multiplicativo que não depende de n, o mesmo não

se passa com a terceira que é n vezes maior que a segunda.

Uma noção menos exigente de ordem de crescimento, usualmente considerada, diz-nos que as duas

primeiras funções (1000n2 e n2) têm a mesma ordem de crescimento. Mais precisamente:

Definição/Notação 3 (“ Θ -notation”, ou “big theta notation”) :

Designa-se por Θ(g) o conjunto das funções que têm o mesmo comportamento assimptótico da função g.

Mais precisamente:

Θ(g) = { f :∃c1 ,c2 ∈R +∃n0 ∈N0∀n≥n0c1g(n) ≤ f (n) ≤ c2g(n)}

E, em vez de escrever f ∈ Θ(g) , escreve-se f = Θ(g) que se lê como se segue “f é um big theta de g”.

De acordo com esta definição, diz-se que o comportamento assimptótico de f é idêntico ao de g, ou que

f e g têm a mesma ordem de grandeza, ou a mesma ordem de crescimento, assimptótico (ou,

simplesmente, que f e g são da mesma ordem), se existem constantes reais positivas, c1 e c2, tais que, a

partir de uma certa ordem n0, f(n) está entre c1g(n) e c2g(n).

Como estamos a assumir que as nossas funções são positivas (pelo menos) a partir de uma certa

ordem, podemos descrever a condição f = Θ(g) em termos da razão entre o valor de f(n) e g(n), obtendo

talvez uma melhor visão do significado de f e g terem a mesma ordem de crescimento (tal acontece

quando, a partir de uma certa ordem n0, tal razão está entre limiares fixos):

Page 15: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

401

f =Θ(g) sse ∃c1 ,c2 ∈R+∃n0 ∈N0

∀n≥n0c1 ≤

f (n)g(n)

≤ c2

Observação 2 :

a) Como é intuitivamente necessário, se o comportamento assimptótico de f é idêntico ao de g, então o

comportamento assimptótico de g deve ser idêntico ao de f, e a definição dada satisfaz este requisito

(óbvio). De facto, se existem constantes reais positivas, c1 e c2, tais que

existe um n0 tal que: c1g(n) ≤ f(n) ≤ c2g(n), para qualquer n ≥ n0

então (como estamos a supor que as nossas funções são positivas a partir de uma certa ordem, podemos

passar ao quociente e, escrever35)

existe um n0 tal que:

c1 ≤f (n)g(n)

≤ c2, para qualquer n ≥ n0

donde sai que

existe um n0 tal que:

1c2

≤g(n)f (n)

≤1c1

, para qualquer n ≥ n0

e portanto, existem constantes reais positivas d1 (= 1/c2) e d2 (= 1/c1), tais que

existe um n0 tal que: d1f(n) ≤ g(n) ≤ d2f(n), para qualquer n ≥ n0

(com pretendíamos).

b) Analogamente, para que as nossas definições façam sentido intuitivamente, terá de ter-se que se f cresce

mais lentamente que g, então f e g não crescem com a mesma ordem de grandeza. Que este requisito

intuitivo se verfica pode verificar-se facilmente, como se segue.

Suponha-se, por absurdo, que existiam f e g tais que f = o(g) e f = Θ(g). Ora, f = Θ(g) implica que

existem constantes reais positivas, c1 e c2, tais que, a partir de uma certa ordem n0, c1g(n) ≤f(n)≤c2g(n),

Logo, em particular, existe uma ordem n0 a partir da qual:

c1 ≤f (n)g(n)

Mas tal é impossível, pois como f = o(g), existirá uma ordem n1, a partir da qual (por exemplo)

f (n)g(n)

≤c12

obtendo-se uma contradição para valores de n maiores que o máximo entre n0 e n1.

c) Afirmar que f = Θ(g) é equivalente a afirmar que

∃c1 ∈R +∃n0 ∈N0∀n≥n0c1g(n) ≤ f (n) ∧

∃c2 ∈R +∃n0 ∈N0∀n≥n0 f (n) ≤ c2g(n)

Podemos ainda dar uma outra definição equivalente da condição f = Θ(g) (onde entra uma só constante

real), como se mostra a seguir:

Se f = Θ(g), então (tal como em a) da observação anterior) existem constantes reais positivas, c1 e c2, e

existe um n0 tais que

35 Onde o n0 poderá ter de ser maior (que “o n0 anterior”) para garantir que g(n) é positiva a partir daí.

Page 16: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

402

c1 ≤f (n)g(n)

≤ c2, para qualquer n ≥ n0 (*)

e

1c2

≤g(n)f (n)

≤1c1

, para qualquer n ≥ n0 (**)

e, considerando c igual ao máximo entre c2 e 1/c1, de (*) e (**), obtém-se que

f (n)g(n)

≤ c , para qualquer n ≥ n0

e

g(n)f (n)

≤ c , para qualquer n ≥ n0

Por outro lado, se para algum real positivo c, se tem que

∃n0 ∈N0∀n≥n0 ( f (n) ≤ cg(n)∧ g(n) ≤ cf (n))

então

existe um n0 tal que:

1c≤f (n)g(n)

≤ c , para qualquer n ≥ n0

Logo, a definição 2 é equivalente à seguinte definição:

f =Θ(g) sse ∃c∈R +∃n0 ∈N0∀n≥n0

( f (n) ≤ cg(n)∧ g(n) ≤ cf (n))

Refira-se também que embora

limn→∞

f (n)g(n)

= b, com b ≠ 0 e b ≠ ∞

seja uma condição suficiente para se ter f = Θ(g) (como é fácil de verificar36), ela não é uma condição

necessária.

Por exemplo, se f(n) = 2n, se n é impar e f(n) = 4n, se n é par, e se g(n) = 2n, então o limite f(n)/g(n)

não existe e, no entanto, 1g(n) ≤ f(n) ≤ 2g(n), para qualquer n≥1 (pelo que f = Θ(g)).

Saliente-se ainda, a propósito, que quando as funções f e g se podem estender a funções, de variável

real, diferenciáveis em |R+, então podemos recorrer à regra de Cauchy para o cálculo do

limn→∞

f (n)g(n)

regra que recordamos a seguir37 (formulada para os casos que nos interessam):

Regra de Cauchy:

Se

limx→+∞

f (x) = limx→+∞

g(x) = +∞, e se f e g são diferenciáveis num intervalo ]a, +∝[, com

g' (x) ≠ 0 nesse

intervalo, então se existir o limite

limx→+∞

f ' (x)g' (x)

, também existe o

limx→+∞

f (x)g(x)

e têm o mesmo valor.

36 Basta considerar a ordem n0 a partir da qual

f (n)g(n)

− b ≤δ , com δ = b2

e definir

c1 =b2

e c2 =3b2

.

37 Alguns autores (como [3], página 29, ou [30], página 304) chamam a esta regra de regra de L´Hôpital (ou L’Hospital). Noentanto, de acordo com p.ex. J.S. Guerreiro, ([24], páginas 39 a 43), a regra de L’Hospital aplica-se a outros casos.

Page 17: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

403

Crescimento assimptótico não mais rápido: “big-Oh notation”

Introduzimos duas notações, o(g) e Θ(g), para caracterizar as classes de funções que (informalmente)

crescem mais devagar ou com a mesma ordem de grandeza que uma função g.

Ora, muitas vezes, nós não estamos interessados em (ou não é fácil) ser tão precisos, e, para uma certa

função f, basta-nos saber que ela não cresce “mais depressa” que uma dada função g, à parte uma constante

multiplicativa, isto é, que existe uma constante positiva c e uma ordem a partir da qual f(n) ≤ cg(n). Para

descrever tal situação introduziu-se também uma notação própria.

Definição/Notação 4 (“O- notation”, ou “big-Oh notation”) :

Designa-se por O(g) o conjunto das funções (assimptóticamente) limitadas superiormente por g (a menos

de uma constante multiplicativa). Mais precisamente:

Ο(g) = { f :∃c∈R +∃n0 ∈N0∀n≥n0 (0 ≤) f (n) ≤ cg(n)}

E, em vez de escrever f ∈ O(g) , escreve-se f = O(g) que se lê como se segue “f é big oh de g” (ou somente

“f é oh de g”).

Observação 3 :

a) Alguns autores (p.ex. [3], pág. 32) definem a classe de funções o(g) como sendo igual a O(g)-Θ(g).

De acordo com a definição aqui dada de o(g) (coincidente com a de muitos autores), é imediato que

se f=o(g) ∨ f=Θ(g) então f=O(g) (i.e., mais precisamente, f∈o(g) ∨ f∈Θ(g) ⇒ f∈O(g)).

No entanto, ao contrário do que é dito em [30] (páginas 303 a 306), o recíproco nem sempre se

verifica. Por exemplo, se f(n) = n1+sen(n) e g(n) = n2, então f(n)=O(g(n)), mas não se tem f(n)= Θ(g(n))

nem f(n)=o(g(n)).

b) Por outro lado, refira-se que nem sempre podemos comparar a ordem de grandeza de duas funções f e g,

recorrendo à notação-O. Por exemplo, como se refere em [9] (pág. 31), se f(n) = n1+sen(n) e g(n) = n,

então nem f(n)=O(g(n)), nem g(n)=O(f(n)).

c) Compare-se a definição de O(g) e de o(f): enquanto no primeiro caso a condição f(n) ≤ cg(n) apenas se

tem de verificar para uma certa constante (real positiva) c, no segundo caso ela verifica-se para qualquer

constante (real positiva) c. Intuitivamente, quando f=o(g), f(n) torna-se insignificante relaticamente a

g(n), à medida que n se aproxima do infinito.

d) Notar que se pode ter f=O(g), mesmo que f(n)>g(n) para todo o n. O essencial quando escrevemos

f=O(g) é que (a partir de uma certa altura) f(n) é majorada por cg(n), para alguma constante c.

e) Tal como se pode usar a notação-o numa expressão, também se pode usar a notação-O numa expressão,

com um significado idêntico. Uma fórmula envolvendo um termo da forma O(g(n)) é designada por

vezes de uma expressão assimptótica.

f) Estas notações podem generalizar-se a funções reais de variável real, comparando a ordem de grandeza de

duas funções f(x) e g(x), quando x→+∞:

Page 18: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

404

f =Ο(g) sse ∃c∈R+∃x0∈R+∀x≥x0

(0 ≤) f (x) ≤ cg(x)

Estamos a assumir que as funções em causa não são negativas, senão deveríamos considerar os seus

módulos na condição do lado direito.

Mais ainda, a ordem de grandeza de duas funções pode ainda ser comparada não só quando o seu

argumento tende para infinito, mas mesmo quando se aproxima de um determinado valor a (no qual

poderão não estar definidas), devendo contudo então tal ser especificado na notação em causa:

f (x) =Ο(g(x)), quando x ≠ → a , sse ∃c∈R +∃ε>0∀0< x−a <ε f (x) ≤ c g(x)

(não se justificando, nestes casos, assumir a hipótese da não negatividade).

Assim, por exemplo, como38

1+ x ≤ ex ≤ 1+ x + x2, para |x|≤1 (

1+ x ≤ ex verifica-se mesmo

para todo o real x), podemos escrever

ex = 1+ x +Ο(x 2), quando x→ 0

salientando assim que a aproximação

ex por

1+ x é bastante boa quando x→0.∇

Devemos chamar a atenção que o facto de sabermos que f(n)=O(g(n)), nos dizer pouco sobre a ordem de

crescimento de f(n): apenas nos diz que para alguma constante positiva c, a partir de uma determinada

ordem f(n) ≤ cg(n). Mas tal não significa que as ordens de crescimento de f(n) e g(n) sejam semelhantes: o

facto de f(n)=O(g(n)) não impede que também se possa ter f(n)=O(h(n)) para h uma função crescendo para

infinito muito mais lentamente que g.

Por exemplo, 3n = O(n3), mas também 3n = O(n2), assim como 3n = O(n). Se pretendemos uma

descrição mais precisa da ordem de crescimento de 3n devemos recorrer por exemplo à notação theta, tendo-

se 3n=Θ(n). Alguns autores referem que, infelizmente, por vezes na literatura se utiliza a notação O como

se tivesse o mesmo significado que a notação Θ.

A grande vantagem da notação O é que nos permite abstrair de detalhes não importantes, e concentrar

nas características essenciais, p.ex. quando pretendemos ter uma ideia da complexidade máxima de um

algoritmo.

De acordo com [42] (pág. 44) usamos, em geral, a notação-O com três diferentes propósitos:

• para limitar (majorar) o erro que cometemos quando ignoramos “pequenos termos” em fórmulas

matemáticas;

• para limitar (majorar) o erro que cometemos quando ignoramos partes de um programa que contribuem

reduzidamente para o custo global da execução do programa;

• para caracterizar programas em função do custo máximo da sua execução.

38 Recordar que

ex = 1+ x +x 2

2!+x 3

3!+ ...= x i

i!i= 0

∑ .

Page 19: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

405

Crescimento assimptótico não mais lento: “big-omega notation”

Tal como podemos limitar superiormente a ordem de grandeza de uma função f(n), recorrendo à notação O,

também podemos limitar inferiormente tal ordem de grandeza.

Definição/Notação 5 (“ Ω - notation”, ou “big-omega notation”) :

Designa-se por Ω(g) o conjunto das funções (assimptóticamente) limitadas inferiormente por g (a menos

de uma constante multiplicativa). Mais precisamente:

Ω(g) = { f :∃c∈R +∃n0 ∈N0∀n≥n0cg(n) ≤ f (n)}

E, em vez de escrever f ∈ Ω(g) , escreve-se f = Ω(g) que se lê como se segue “f é big omega de g” (ou

somente “f é omega de g”).

É imediato de verificar que

f = Θ(g) sse f = O(g) ∧ f = Ω(g)

Mais alguns comentários sobre o significado e utilização destas notações

Antes de estabelecermos alguns resultados sobre as notações assimptóticas introduzidas (alguns dos quais

podem ser utilizados para manipular algebricamente expressões envolvendo estas notações), efectuemos

mais alguns comentários genéricos sobre o seu significado e utilização.

Como referimos, se f traduz o custo da execução de um algoritmo, estamos essencialmente interessados

no valor de f(n) para grandes valores do input n. Para tais input’s, o valor exacto da expressão f(n) não é

muito relevante, e as dificuldades técnicas que podem ocorrer na caracterização matemática precisa de f(n),

muitas vezes “não pagam o trabalho dessa caracterização”39. Procuramos, assim, ter uma maneira

expedita de poder caracterizar a ordem de grandeza dos diferentes algoritmos, limitando ao máximo os

detalhes matemáticos envolvidos nessa análise, com o fim de distinguir os vários algoritmos em grandes

classes em função da sua ordem de grandeza assimptótica. Estas notações permitem-nos traduzir essa ordem

de grandeza, de uma forma simples e precisa (precisa, desde que não se pretenda extrair delas mais

informação do que elas podem dar).

Por exemplo, pode não ser fácil de caracterizar a expressão explícita de f(n), mas ser fácil de mostrar

que f(n) é um O de uma certa expressão de n, que podemos designar de g(n) . O custo do algoritmo será

nesse caso inferior a g(n) (para valores grandes de n e à parte uma constante multiplicativa); se a ordem de

g for “aceitável”, podemos então optar por escolher o algoritmo, sem nos preocuparmos em obter uma

caracterização mais precisa da sua ordem de grandeza.

Analogamente, poderá ser fácil mostrar que f = Ω(g). Se g(n) for p.ex. da forma cn, com c>1, não vale

a pena perder tempo a caracterizar a ordem de grandeza precisa do algoritmo: ele só poderá servir para

pequenos valores de n.

39 Nomeadamente quando se pretende que f(n) traduza o tempo de execução do algoritmo através da análise de todas as

operações realizadas (e não apenas das mais importantes).

Page 20: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

406

O custo da complexidade de um algoritmo para um input n depende, em geral, das características do

particular input de tamanho n em questão, em cujo caso se costuma fazer uma análise do que se passa no

pior caso, em média e, por vezes também, no melhor caso (como já referimos a propósito da ordenação de

listas). O custo do algoritmo na pior situação é relevante e é um limite superior ao custo da complexidade

do algoritmo para qualquer input com a mesma dimensão. Se na pior situação o custo do algoritmo é da

ordem de g(n) (i.e. é um Θ(g(n)), então podemos concluir que, seja qual for o input de dimensão n, o seu

custo é um O(g(n)). Frequentemente, os algoritmos são comparados em função da ordem de grandeza do

seu custo, no pior caso.

Por outro lado, a notação Ω pode também servir para estabelecer limites ao melhor que se consegue,

em relação a um determinado problema. Se conseguirmos provar (como é o caso na ordenação de listas)

que a ordem de grandeza de qualquer algoritmo (com certas características) que resolva um determinado

problema é necessáriamente superior ou igual a uma certa expressão g(n) (é um Ω(g)), e se estivermos em

presença de um algoritmo cujo custo f(n) seja da ordem de grandeza de g(n), então não vale muito a pena

procurar um algoritmo melhor, pois assimptoticamente “não se arranja melhor” (à parte constantes

multiplicativas).

Devemos, contudo, saber interpretar estas notações e, como se disse atrás, não pretender extrair delas

mais informação do que elas podem dar.

Por exemplo, o facto da complexidade f(n) de um dado algoritmo ser um O(g(n)) diz-nos apenas que

existe uma constante c tal que, a partir de certa ordem n0, f(n) ≤ cg(n). Por um lado, como já referimos, a

ordem de f(n) pode ser mesmo muito inferior à de g(n). Por outro lado (no sentido contrário), embora

tenhamos a garantia de que f(n) ≤ cg(n) a partir de uma certa ordem, o valor da ordem (n0) e da constante (c)

em causa estão interligados, e pode ser que essa ordem seja demasiado grande para as instâncias do

problema com que nos vamos debater na prática. Mais geralmente, o facto de dois algoritmos terem custos

f1(n) e f2(n) até com a mesma ordem de grandeza, isto é f1=Θ(f2), não significa, a priori, que um não seja

preferível a outro. Por exemplo, se f1(n) = 10100f2(n), continua a ter-se que f1=Θ(f2), mas f1 é claramente

preferível a f2. Assim, não é totalmente verdade que se possa dizer que o conhecimento da expressão

explícita da função de custo não é relevante. O que acontece na prática, felizmente, é que quando f(n) traduz

o custo de um dado algoritmo e estabelecemos que f(n)=Θ(g(n)), normalmente tal significa que se

conseguiu mostrar que40 f(n) = cg(n) + h(n), com c uma constante relativamente pequena e h(n)=o(g(n)), e

em que “o zero” h(n) normalmente se torna muito rapidamente insignificante41 face a g(n).

Para terminar estas observações, refira-se o que se diz em [42] (páginas 37 e 38) a propósito de

algumas ordens de crescimento típicas que ocorrem no âmbito da análise de algoritmos, e das

características genéricas dos algoritmos que dão origem a tais ordens:

40 Quando f(n) = cg(n) + h(n), com h(n)=o(g(n)), dizemos por vezes (informalmente) que f(n) é proporcional a g(n).41 Este aspecto, que se verifica na prática, é importante, pois do ponto de vista teórico uma função h(n)=10100000n é um o(n2),mas salvo para inputs enormes, escolheríamos sempre um algoritmo de complexidade n2 face a um algoritmo de complexidade10100000n.

Page 21: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

407

• Θ(1) (designa um tempo de computação/complexidade constante)

Situação (pouco usual) em que as instruções do programa são executadas um número fixo de vezes,

independentemente do valor do input n.

• Θ(logan) (tempo de execução/complexidade logarítmico)

Crescimento um pouco mais lento que n. Numa descrição informal, esta situação ocorre em programas

que resolvem um problema grande, transformando-o numa série de problemas menores, tendo-se que

em cada passo o tamanho do problema é cortado por uma fracção constante. Para muitos efeitos

práticos, podemos considerar que o tempo de execução é menor que uma constante grande. A base do

logaritmo muda o valor de tal constante, mas não muito: quando n é mil, log10n é 3 e log2n é

(aproximadamente) 10; quando n é um milhão, logan é apenas o dobro desses valores; quando n dobra,

logan cresce por uma constante, e logan apenas dobra quando n cresce para n2.

• Θ(n) (complexidade linear)

Situação que ocorre em geral quando um “pequeno trabalho de processamento” é realizado sobre cada

elemento do input. Trata-se da melhor situação possível para um algoritmo que tem de processar n

elementos de entrada (input) ou de produzir n elementos de saída. Quando n dobra, o mesmo se verifica

com o tempo de execução.

• Θ(n logan) (complexidade n logan)

Esta situação ocorre tipicamente em programas que resolvem um problema, partindo-o em problemas

mais pequenos, que são resolvidos independentemente, e cuja solução é depois combinada de modo a

resolver o problema inicial (divide and conquer algorithms). Quando n é 1 milhão, nlogan é

aproximadamente 20 milhões; quando n é 2 milhões (dobrando portanto), nlogan é aproximadamente

42 milhões, um pouco mais que o dobro.

• Θ(n2) (complexidade quadrática)

Situação que ocorre em geral quando os elementos são processados aos pares, normalmente com um

ciclo dentro de outro ciclo (como nos métodos directos/elementares de ordenação). Só servem na prática

para resolver problemas de dimensão relativamente pequena. Quando n é mil, n2 é um milhão; quando

n dobra, n2 quadriplica.

• Θ(n3) (complexidade cúbica)

Situação que ocorre em geral quando os elementos são processados em triplos, normalmente com três

ciclos encaixados (triple-nested loop). Só servem na prática para resolver problemas de pequena

dimensão. Quando n é 100, n3 é um milhão; quando n dobra, n3 fica 8 vezes maior.

• Θ(2n) (complexidade exponencial)

Situação que ocorre em geral em algoritmos que tentam resolver problemas à (chamada) “força bruta”

(brute-force), analisando todas as possíveis combinações. Em geral estes algoritmos são inúteis na

prática. Quando n é 20, 2n é um milhão; quando n dobra, 2n é igual ao quadrado do valor anterior.

Em geral, a função de complexidade de um programa pode ser expressa por uma constante

(normalmente pequena) vezes um destes termos (acabados de referir), que podemos designar informalmente

de termo dominante, mais um conjunto de termos de menor ordem de grandeza. (Grosso modo, o valor da

constante, coeficiente do termo dominante, tem a ver com o número de instruções do ciclo de dentro.) Para

Page 22: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

408

grandes valores de n, o efeito do termo dominante é que prevalece; para valores não muito grandes de n, a

contribuição dos outros termos pode ser relevante e a comparação dos algoritmos é mais difícil.

Alguns resultados relacionados com as notações introduzidas

Vejamos, para terminar este capítulo, alguns resultados relacionados com as noções introduzidas e alguns

exemplos de cálculo da ordem de grandeza de funções.

Nos resultados a seguir quando uma das notações o, ϖ , Θ , O e Ω aparece nos dois membros da

igualdade, esta deve ser interpretada como ⊆.

Assim, por exemplo, cO(f(n)) = O(f(n)), deve ser interpretado como cO(f(n)) ⊆ O(f(n)) (com c{g(n): ...}

significando {cg(n): ...}), isto é, qualquer que seja g(n)∈O(f(n)), existe h(n)∈O(f(n)) tal que cg(n) = h(n).

Isto é, informalmente, no lado esquerdo (por exemplo) O(f(n)) significa “qualquer que seja

g(n)∈O(f(n))” e no lado direito O(f(n)) significa “existe g(n)∈O(f(n))”

Teorema 1 (algumas propriedades gerais das notações o, ϖ, Θ, O e Ω):

i) Reflexividade:

f(n) = Θ(f(n))

f(n) = O(f(n))

f(n) = Ω(f(n))

ii) Simetria:

f(n) = Θ(g(n)) ⇔ g(n) = Θ(f(n))

iii) transitividade:

f(n) = Θ(g(n)) ∧ g(n) = Θ(h(n)) ⇒ f(n) = Θ(h(n))

f(n) = O(g(n)) ∧ g(n) = O(h(n)) ⇒ f(n) = O(h(n))

f(n) = Ω(g(n)) ∧ g(n) = Ω(h(n)) ⇒ f(n) = Ω(h(n))

f(n) = o(g(n)) ∧ g(n) = o(h(n)) ⇒ f(n) = o(h(n))

f(n) = ϖ(g(n)) ∧ g(n) = ϖ(h(n)) ⇒ f(n) = ϖ(h(n))

iv) f(n) = O(g(n)) ⇔ g(n) = Ω(f(n))

f(n) = o(g(n)) ⇔ g(n) = ϖ(f(n))

v) f(n) = Θ(g(n)) ⇔ f(n) = O(g(n)) ∧ f(n) = Ω(g(n))

vi) f(n) = o(g(n)) ∨ f(n) = Θ(g(n)) ⇒ f(n) = O(g(n))

f(n) = ϖ(g(n)) ∨ f(n) = Θ(g(n)) ⇒ f(n) = Ω(g(n))

vii) Se c é uma constante real positiva, então:

c O(f(n)) = O(f(n)) (ou, equivalentemente, qualquer que seja g, se g(n)= O(f(n)), então cg(n)= O(f(n)))

c Ω(f(n)) = Ω(f(n))

c Θ(f(n)) = Θ(f(n))

c o(f(n)) = o(f(n))

c ϖ(f(n)) = ϖ(f(n))

viii) Se f(n) = Θ(g(n)), então f(n) não é um o(g(n)) (i.e. se f(n) ∈ Θ(g(n)), então f(n) ∉ o(g(n)))

ix) Se f(n) = o(g(n)), então f(n) não é um Θ(g(n)) (i.e. se f(n) ∈ o(g(n)), então f(n) ∉ Θ(g(n)))

x) o(g(n)) ∩ ϖ(g(n)) = ∅

Page 23: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

409

Demonstração :

Exercício.

No próximo teorema enunciam-se mais algumas propriedades gerais relacionadas com a notação-O

(operações que podemos efectuar com essa notação). Deixa-se como exercício verificar quais dessas

propriedades são válidas, ou adaptáveis, para o caso das outras notações.

Teorema 2 (mais algumas propriedades gerais da notação O):

i) 42 O(f(n)) + O(g(n)) = O(max(f(n),g(n))

ii) O(f(n)) + O(f(n)) = O(f(n))

iii) O(O(f(n))) = O(f(n))

ii) O(f(n)) * O(g(n)) = O(f(n) * g(n))

iii) f(n) * O(g(n)) = O(f(n) * g(n))

Demonstração :

Exercício.

Seguem-se alguns exemplos de determinação da ordem de grandeza de certas funções. Escreveremos

resultado/exemplo se se tratar da ordem de grandeza de “classes” de funções (funções de uma certa forma),

ou da ordem de grandeza de funções que tem particular interesse conhecer. Escreveremos só exemplo, se se

tratar acima de tudo de utilizar os resultados enunciados para calcular a ordem de grandeza de uma função

específica.

Resultado/Exemplo 1 :

Quaisquer que sejam as constantes reais, α e β:

nα = o(nβ ) sse α < β

Demonstração :

⇐: se α < β, então (β-α>0 e)

limn→∞

nβ= limn→∞

nαnβ −α= limn→∞

1nβ −α

= 0

⇒:Demonstremos o contra-recíproco:

Se não se tem α < β, então:

i) ou α = β, e

limn→∞

nβ= 1, pelo que nα não é um o(nβ), mas sim um Θ(nβ)

ii) ou α > β, e

limn→∞

nβ= limn→∞

nβ nα−β

nβ= limn→∞

nα−β =∞, pelo que nα=ϖ(nβ) (e nα não é um o(nβ))

42 Se estivessemos a permitir que as nossas funções pudessem assumir valores negativos, então i) já não poderia ser assimenunciado: no lado direito teria de estar O(max(|f(n)|,|g(n)|). Ter-se-ia também O(f(n))+O(g(n)) = O(|f(n)|+|g(n)|).

Page 24: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

410

Resultado/Exemplo 2 :

Qualquer que seja o polinómio

p(n) = aini

i= 0

d

∑ (com

ad > 0 ), tem-se que

p(n) =Θ(nd )

Demonstração :

Imediato, pois

limn→∞

p(n)nd

= ad ≠ 0,∞

Resultado/Exemplo 3 :

Quaisquer que sejam as constantes reais, a e b, com a>1:

nb = o(an )Demonstração :

Pode provar-se que

limn→∞

nb

an= 0, por exemplo, das duas maneiras seguintes:

Alternativa 1:

i) Começar por provar, por indução em b, que

limx→∞

xb

ax= 0 (com x real), para qualquer natural b:

Base:

limx→∞

x0

ax= 0

Seja b≥0.

HI:

limx→∞

xb

ax= 0

Tem-se:

limx→∞

xb+1

ax=∞

∞= (regra de Cauchy) = lim

x→∞

(b + 1)xb

ax lna= (por HI) 0

ii) Se b é um real não negativo, então

0 ≤ xb

ax≤x b

ax.

Logo, como, por i),

x b

ax x→∞ → 0 , tem-se

xb

ax x→∞ → 0

iii) Se b é um real negativo, então

xb

ax=

1x−bax x→∞

→ 0

Alternativa 2 (ver p.ex. [18], pág. 144):

Seja

zn =nb

an. Existe o limite

limn→∞

zn+1zn

= limn→∞

( 1a( n +1n)b ) =

1a

.

Logo (ver pág. 135 do mesmo livro) também existe o limite

limn→∞

znn e é igual ao limite anterior:

limn→∞

znn = limn→∞

zn+1zn

=1a

< 1

Mas então existe

d ∈] 1a,1[ tal que, a partir de uma certa ordem,

znn < d .

Logo

0 < zn < dn e portanto

limn→∞

zn = 0

Page 25: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

411

Resultado/Exemplo 4 :

Qualquer que seja a constante real a>1:

an = o(n!)

Demonstração :

Aplicando a mesma técnica da alternativa 2 da demonstração anterior, tem-se:

Se

zn =an

n!, então

limn→∞

zn+1zn

= limn→∞

an +1

= 0 .

Logo:

limn→∞

znn = limn→∞

zn+1zn

= 0

Mas então existe

d ∈]0,1[ tal que, a partir de uma certa ordem,

znn < d .

Logo

0 < zn < dn e

limn→∞

zn = 0

Observação 4 (Logaritmos):

A função logaritmo desempenha um papel importante na análise de algoritmos, justificando-se algumas

considerações sobre ela.

Em matemática o logaritmo mais importante e usado é talvez o logaritmo natural, isto é o logaritmo

de base e (=2.71828...), usando-se uma notação própria para designar tal logaritmo: ln = loge.

Em computação o logaritmo binário (logaritmo de base 2) é talvez o mais usado, justificando-se que

também se introduza uma notação própria para o designar, e muitos autores de ciência da computação

consideram a seguinte abreviatura: lg = log2.

O menor inteiro maior que

lgn , i.e.

lgn , é o número de bits necessários para representar n em

notação binária, do mesmo modo que

lg10 n é o número de dígitos necessários para representar n em

notação decimal.

Em parte, a importância do logaritmo de base 2 em ciência da computação advém também do facto de

muitos algoritmos e estruturas de dados envolverem uma partição de um problema em duas partes, dando

origem a algoritmos de complexidade relacionada com log2n (ver exemplos no próximo capítulo).

De qualquer forma, como a mudança de base de um logaritmo apenas altera o valor do logaritmo por

um factor constante:

logb x =loga xloga b

a base que é usada para os logaritmos dentro das notações assimptóticas é basicamente irrelevante. Por essa

razão, no âmbito dessa análise assimptótica, por vezes escreve-se (e poderemos escrever aqui) log sem

especificar a base, assumindo que se trata de um logaritmo numa base maior que 1, mantendo-se a notação

ln e lg sempre que quisermos especificar que se trata do logaritmo na base, respectivamente, e e 2.

Por outro lado, são ainda usuais as seguintes abreviaturas com logaritmos (onde a base das várias

ocorrências de log se assume ser a mesma):

log log x = log(log x) e logbx = (log x)b (com b um real positivo)

Page 26: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

412

Para terminar esta observação, e atendendo à importância dos logaritmos, recordemos algumas das suas

propriedades essenciais (onde, salvo menção em contrário, x, a, b e c designam quaisquer reais positivos):

• (definição, com a≠1 e y real qualquer:)

loga x = y⇔ ay = x

• Se a>1, a função

loga x é estritamente crescente

a loga x = x•

loga ax = x

loga 1= 0

loga a = 1

loga (bc) = loga b + loga c

(propriedade que pode ser usada para transformar produtórios em somatórios43)

loga (xb ) = b loga x

loga (1b) = − loga b

• (mudança de bases:)

logb x =loga xloga b

, ou de outro modo,

loga x = loga b× logb x

logb a =1

loga b

a logb x = x logb a

• (derivada:)

(lnx ′ ) =1x e (usando a conversão de bases)

(loga x ′ ) = (loga e lnx ′ ) =loga ex

Pode ainda referir-se que

lge = log2 e ≈ 1.44 ,

ln2 ≈ 0.7 e

lg10 = log2 10 ≈ 3.32 , bem como as seguintes

desigualdades:

lgx < x, para x ≥ 1 (onde, recorde - se, lgx = log2 x)

• Se um natural n é uma potência de 2,

n = 2k , então

k = lgn

Se n não é potência de 2, então existe um inteiro k tal

2k < n < 2k+1, tendo-se

k = lgn e k +1 = lgn

E portanto, também, em qualquer dos casos

2 lgn ≤ n < 2 lg n +1

n ≤ 2 lgn < 2n

n2

< 2 lgn ≤ n

• Para x>-1, tem-se

x1+ x

≤ ln(1+ x) ≤ x (verificando-se a igualdade apenas para x=0).

Observação 5 (Aproximações de somatórios por integrais):

Os resultados a seguir podem ser úteis para obter majorações e minorações de somatórios, recorrendo a

integrais:

43 Se bi>0, para i=1,...,n, então

loga ( bii=1

n

∏ ) = loga bii=1

n

∑ , onde

bii=1

n

∏ = b1 × b2 × ...× bn (= 1, se n = 0) .

Page 27: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

413

• Se f é uma função contínua decrescente e a e b são inteiros (com a ≤ b), então:

f (x)dxa

b+1

∫ ≤ f (i)i= a

b

∑ ≤ f (x)dxa−1

b

• E, analogamente, se f é crescente, então:

f (x)dxa−1

b

∫ ≤ f (i)i= a

b

∑ ≤ f (x)dxa

b+1

Resultado/Exemplo 5 :

a)

lnn = o(nα ) , para qualquer real α>0

b) Mais geralmente, para qualquer base c>1 e qualquer real α>0,

logc n = o(nα )

Demonstração :

a) Imediato, pois

limx→∞

lnxxα

=∞

∞= (pela regra de Cauchy) lim

x→∞

1x

αxα−1 = limx→∞

1αxα

= 0

b) Podemos calcular o limite como em a), ou usar resultados anteriores como a seguir:

lnn = o(nα ) , por a).

logc x = logc e× lnx

Logo, pelo teorema 1 – vii),

logc x = o(nα )

Podemos ainda generalizar o resultado anterior, como se segue:

Resultado/Exemplo 6 :

Para qualquer base c>1 e quaisquer reais b>0 e α>0,

logb n = o(nα ) , com

log = logc

Demonstração :

Como vimos na demonstração do resultado/exemplo 3,

limx→∞

xb

ax= 0 , para quaisquer reais a e b com a>1

Logo, como

lognn→∞

→ ∞ , substituindo, na equação anterior, x por logn, obtém-se:

limn→∞

(logn)b

a logn= 0

Mas

cα > 1. Logo podemos sustituir na igualdade anterior a por

cα , obtendo-se

limx→∞

(logn)b

(cα )logn = 0 e (logn)b

(cα )log n =logb n

(c logn )α=

logb nnα

Page 28: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

414

Resultado/Exemplo 7 :

n lnn = o(n2 )

Demonstração :

Imediato, pois

limx→∞

x lnxx2 = lim

x→∞

lnxx

=∞

∞= (pela regra de Cauchy) lim

x→∞

1x1

= limx→∞

1x

= 0

Resultado/Exemplo 8 :

a)

n!=ϖ (2n )

b)

n!= o(nn )

c)

lg(n!) =Θ(n lgn)

Demonstração :

a) Imediato, pois pelo resultado/exemplo 4,

an = o(n!) , para qualquer real a>1, e portanto também para

a=2. Logo o resultado sai do teorema 1-iv).

b) Aplicando a mesma técnica da demonstração do resultado/exemplo 4, tem-se:

Se

zn =n!nn

, então44

limn→∞

zn+1zn

= limn→∞

nn

(n +1)n=

1

( n +1n)n

=1

(1+1n)n

→1e

Logo:

limn→∞

znn = limn→∞

zn+1zn

=1e

< 1

Mas então existe

d ∈] 1e,1[ tal que, a partir de uma certa ordem,

znn < d .

Logo

0 < zn < dn e portanto

limn→∞

zn = 0

c) i) Tem-se (para qualquer n≥1):

lg n! =

lg(n × (n −1) × ...×1)

= lgn + lg(n-1) + ... + lg1 (lg é uma função crescente)

≤ lgn + lgn + ... + lgn (n termos)

= n lgn

Logo

lg(n!) =O(n lgn)

ii) Tem-se (para qualquer n≥1):

lg n! = lgn + lg(n-1) + ... + lg1 (lgi ≥0, para i=1,...,n)

44 Recordar que

ex = limn→∞

(1+xn)n , para qualquer real x.

Page 29: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

415

lgn + lg(n −1)+ ...+ lg n2

(

n − n2

+1 termos)

lg n2

+ lg n

2

+ ...+ lg n

2

(lg é uma função crescente)

=

n2

lg n2

(nº de termos45:

n − n2

+1 ≥

n2

)

n2lg( n2)

Mas para n≥4, tem-se

lg( n2) ≥ 12lgn (tem-se mesmo46

lg( n2) >12lgn , para n>4, e

lg( n2) =12lgn ,

se n=4).

Logo, para n≥4, tem-se

lg(n!) ≥ n lgn4 , e portanto

lg(n!) = Ω(n lgn)

iii) E (pelo teorema 1–v)), de i) e ii), conclui-se que

lg(n!) =Θ(n lgn)

(c.q.d.)

Exemplo 9 :

Mostrar que

n3 + 2n = Ω(n2 )

Resolução :

Imediato, pois, se n≥1, então

n3 + 2n ≥ n2 + 2n ≥ n2

Exemplo 10 :

Mostrar que, para qualquer constante k>0,

log(k + n) =Θ(logn) (com

log = logc e c>1)

Resolução :

Como log é crescente, qualquer que seja n≥1,

log(k + n) ≥ logn . Logo

log(k + n) = Ω(logn) .

E, pela mesma razão, qualquer que seja n≥max{2,k},

log(k + n) ≤ log(2n) ≤ log(n2 ) = 2 logn . Logo

log(k + n) =Ο(logn) .

Assim,

log(k + n) =Θ(logn) (c.q.d.)

Exemplo 11 :

Mostrar que existe uma função crescente f tal que f(n) = Θ(1)

45 Tem-se (ver capítulo 4) n/2 + n/2 = n (para n inteiro). Logo n - n/2 +1 = n/2 +1 ≥ n/2 .

46 Tem-se

lg( n2) >12lgn⇔ lgn − lg2 >

12lgn⇔ lgn −1>

12lgn⇔ lgn > 2 . E, como lg é estritamente crescente e

lg 4 = 2 , conclui-se que

lg( n2

) >12

lgn⇔ n > 4 (tendo - se lg( n2

) =12

lgn⇔ n = 4)

Page 30: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

416

Resolução :

Seja

f (n) =n −1n

= 1− 1n

.

Trata-se de uma função crescente e, para qualquer n≥2,

12×1≤ f (n) ≤ 1×1

Exemplo 12 47:

Sem utilizar a fórmula explícita do somatório

ii=1

n

∑ , mostrar que

ii=1

n

∑ =Θ(n2) (com n≥1)

Resolução :

Tem-se:

1+2+...+n ≤ n+n+...+n = n*n=n2

Logo

ii=1

n

∑ =O(n2)

E:

1+2+...+n ≥ 1+1+...+1 = n

Logo

ii=1

n

∑ =Ω(n) .

Mas esta minoração não nos permite concluir o que desejávamos. Para isso precisamos de mostrar que

existe um minorante para o somatório da ordem de grandeza de n2, o que pode ser feito, por exemplo,

como se segue, onde se “deita fora”metade das parcelas, seguindo uma estratégia análoga à do

resultado/exemplo 8-c):

1+ 2+ ...+ (n −1)+ n ≥ n2

+ ...+ (n −1)+ n

≥n2

+n2

+ ...+ n

2

≥n2

×n2

n2×n2

=14× n2

Logo

ii=1

n

∑ =Ω(n2)

E, como

ii=1

n

∑ =O(n2) e

ii=1

n

∑ =Ω(n2) , pode concluir-se que

ii=1

n

∑ =Θ(n2) (c.q.d.)

47 Tirado de [34], pág. 171.

Page 31: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

417

Exemplo 13 :

Determinar a ordem de grandeza de

1ii= 2

n

∑ (onde n≥2)

Resolução :

A função real de variável real 1/x é contínua e decrescente. Assim (ver observação 5):

1ii= 2

n

∑ ≤1xdx

1

n

∫ = lnn − ln1= lnn

e

1ii= 2

n

∑ ≥1xdx

2

n+1

∫ = ln(n +1) − ln 2 > lnn − ln 2

pelo que (justifique)

1ii= 2

n

∑ =Θ(lnn)

(Tem-se mesmo:

limn→∞

1ii= 2

n

lnn= 1, pois

1← lnn − ln 2lnn

1ii= 2

n

lnn≤lnnlnn

→ 1)

Exemplo 14 :

Mostrar que

lg i ≥ n lgn −1.5ni=1

n

∑ (para n≥1).

Resolução :

Como lg é crescente (e lg1=0), tem-se (ver observação 5):

lg ii=1

n

∑ = lg ii= 2

n

∑ ≥ lg xdx1

n

∫ = lge ln xdx1

n

∫ = lge x ln x − x[ ]1n =

lge(n lnn − n +1) = n lgn − n lge+ lge ≥ n lgn − n lge

e o resultado sai, atendendo a que

lge ≈ 1.44 < 1.5

Exemplo 15 (números harmónicos) :

Considere-se o somatório

Hn =1kk=1

n∑ (para n≥1).

O valor Hn é o chamado n-ésimo número harmónico48 (harmonic number) e ocorre por vezes na análise de

eficiência de alguns algoritmos (como ilustraremos no próximo capítulo).

Calculemos a ordem de grandeza de Hn.

Como 1/x é decrescente, tem-se (ver observação 5):

48 Assim chamado por o n-ésimo harmónico produzido por uma sequência de violino ser o som fundamental produzido por umasequência 1/n vezes longa.

Page 32: Capítulo 11 - Ordem de grandeza do crescimento assimptótico: …cee.uma.pt/edu/ed/textosp/Texto11.pdf · interesse em estudar a ordem de grandeza da rapidez do crescimento de funções

418

1kk=1

n∑ = 1+

1ki=2

n∑ ≤ 1+

1xdx

1

n∫ = 1+ lnn (= Ο(1)+O(ln n) = Ο(max(1, lnn)) =49 O(ln n))

pelo que Hn = O(ln n)

e

1kk=1

n∑ =

1ki=1

n−1∑ +

1n≥

1xdx

1

n∫ +

1n

= lnn +1n

(≥ ln n)

pelo que Hn = Ω(ln n)

Logo Hn = Θ(ln n).

E das desigualdades acima igualmente sai que50 Hn = ln n + Ο(1).

Exercícios :

(Tal como temos estado a supor, no que se segue f(n) e g(n) são não-negativas e positivas pelo menos a

partir de uma certa ordem.)

1) Usando a definição da notação Θ, demonstre que max(f(n),g(n)) = Θ(f(n)+g(n))

2) Mostre que, quaisquer que sejam as constantes reais a e b, com b>0, tem-se (n+a)b = Θ(nb)

3) Diga, justificando, se:

a) 2n+1 = O(2n)

a) 22n = O(2n)

4) Demonstre que se α e β são constantes reais tais que α ≤ β, então nα = O(nβ)

5) Demonstre que se f(n) = Θ(g(n)), então

2 f (n ) =Θ(2g(n ))

6) Mostre que

n(n −1)2

=Θ(n2 )

7) Mostre que, para qualquer constante k>0,

log(k × n) =Θ(logn) , com

log = logc e c>1.

(Sugestão: calcule

limn→∞

log(k × n)logn )

8) Mostre que

3n + 5 lgn =Θ(n)

9) Mostre que, qualquer que seja o inteiro positivo k, se tem

i ki=1

n

∑ =Θ(nk+1)

(Sugestão: seguir a mesma estratégia que foi usada no exemplo 12.)

49 Tem-se max(1, lnn) = ln n, para n≥3.

50 Pode mesmo obter-se a seguinte excelente aproximação do n-ésimo número harmónico:

Hn ≈ lnn + γ +112n

, onde γ =

0,57721... é a chamada constante de Euler.