Complexidade de Algoritmos, Notas de estudo de Algoritmos
arnaldo-araujo-11
arnaldo-araujo-11

Complexidade de Algoritmos, Notas de estudo de Algoritmos

10 páginas
50Números de download
1000+Número de visitas
100%de 0 votosNúmero de votos
4Número de comentários
Descrição
Tutorial para o calculo da complexidade de algoritmos
100 pontos
Pontos de download necessários para baixar
este documento
Baixar o documento
Pré-visualização3 páginas / 10
Esta é apenas uma pré-visualização
3 mostrados em 10 páginas
Esta é apenas uma pré-visualização
3 mostrados em 10 páginas
Esta é apenas uma pré-visualização
3 mostrados em 10 páginas
Esta é apenas uma pré-visualização
3 mostrados em 10 páginas

Elementos de análise de programas

David Déharbe∗

DIMAp/UFRN

18 de setembro de 2003

Sumário

1 Introdução 1

2 O que é análise de algoritmos ? 2 2.1 Dicas para avaliar a complexidade de um algoritmo. . . . . . . . . . . . . . . . . . . . . . . . . . 3

2.1.1 Algoritmos iterativos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2.1.2 Algoritmos recursivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.1.3 Considerações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2.2 Comparação de algoritmos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

3 Definições formais 6 3.1 Limite superior: a notação O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 3.2 Limite inferior: a notação Ω . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 3.3 Complexidade exata: a notação Θ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 3.4 Limite superior estrito: a notação o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

4 Exemplo: O problema da soma da maior subseqüência 8 4.1 Um algoritmo cúbico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 4.2 Um algoritmo quadrático . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 4.3 Um algoritmo linear . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

1 Introdução

Um usuário mede a qualidade de um programa através de vários critérios:

• A interface do programa deve facilitar o quanto mais posśıvel o seu uso por um usuário, levando em conta que usuário com diferentes ńıveis de experiência tem comportamentos e exigências diferentes. Por exemplo, um novo usuário irá descobrir as várias funcionalidades de um programa através de uma interface amigável (como o mouse ou a voz), enquanto por razões de produtividade, um usuário experiente prefere ter acesso aos comandos direitamente através do teclado.

• A compatibilidade do programa com outros programas, ou outras versões do mesmo programa. ∗Copyright c©2001,2003 David Deharbe and Universidade Federal do Rio Grande do Norte. Todos os direitos reservados.

1

2 O que é análise de algoritmos ? 2

• A velocidade de execução do programa é também um critério extremamente importante, especialmente em aplicações cient́ıficas onde computações pesadas occorrem.

• A quantidade de memória utilizada pelo programa durante sua execução. Essa quantidade de memória, assim também como a velocidade de execução, são, em geral, diretamente ligados à quantidade de dados processados.

Para a empresa que produz um programa, além de satisfazer seus usuários, outros critérios são usados para medir a qualidade de um programa. Esses critérios têm principalmente a ver com a produtividade da empresa e são:

• A portabilidade do código entre várias plataformas.

• A clareza, ou lisibilidade, do código é extremamente importante, pois quanto mais acesśıvel, mais fácil fazer evoluir o código. Para possibilitar a manutenção de código, é crucial prever uma documentação do programa espećıfica para programadores.

• A reutilisabilidade do código permite que porções de um programa sejam reaproveitadas para desenvolver outros produtos e permitem ganhos óbvios de produtividade. Existe programadores que se especializam na produção de bibliotecas de código que são suficientemente genéricas para ser aproveitadas para várias aplicações. Linguagens modernas vêm com bibliotecas de funções de uso geral (a biblioteca padrão de stdlib para C, STL para C++, JavaBeans para Java).

Neste caṕıtulo introduziremos uma ferramenta formal para medir a o tempo e a memória gastos por algorit- mos. Apresentaremos um problema que pode ser resolvido com algoritmos de velocidade diferentes. A área da computação que estude esse problema é chamada de Complexidade de algoritmos e é o objeto de uma disciplina do seu curso.

2 O que é análise de algoritmos ?

O tempo de execução de um algoritmo e a quantidade de memória que ele utiliza geralmente dependem do tamanho da entrada que ele deve processar. Assim, esperamos que ordenar 10.000 números leva mais tempo que ordenar 10 elementos. Na prática, estamos acostumados a observar que um editor de texto leva mais tempo e consume mais memória quando é aberto com um grande arquivo que com um pequeno, ou que um programa de edição gráfica utiliza mais memória e leva mais tempo para aplicar um filtro a uma imagem grande que a uma imagem pequena. Portanto, em geral, a memória alocada e o tempo de execução de um algoritmo são funções do tamanho da entrada.

É importante enfatizar que sempre tentamos estabelecer uma aproximação da complexidade, pois ela depende de muitos fatores e é uma tarefa quase imposśıvel fazer uma predição totalmente exata de quanto tempo vai durar a execução, ou da quantidade exata de memória que será utilizada.

O tempo de execução e o espaço alocado são os dois fatores formando a complexidade computacional, ou simplesmente complexidade, de um algoritmo. Mais precisamente, um algoritmo tem duas medidas de complexidade:

1. a complexidade temporal, que é aproximativamente o número de instruções que ele executa, e

2. a complexidade espacial, que é a quantidade de memória que ele utiliza durante sua execução.

Ambas complexidades são funções que tem como parâmetro o tamanho da entrada tratada.

2.1 Dicas para avaliar a complexidade de um algoritmo. 3

2.1 Dicas para avaliar a complexidade de um algoritmo.

A complexidade tanto espacial quanto temporal de um algoritmo é estimada em função do tamanho da entrada. Logo é importante estabelecer de que forma o tamanho da entrada influi no comportamento do algoritmo.

Assim, se o algoritmo não é recursivo, não contém iterações e também não utiliza algoritmos que tem essas carateŕısticas, então o número de passos é independente do tamanho da entrada e digamos que a complexidade (temporal) é constante.

2.1.1 Algoritmos iterativos

Se o algoritmo tem como parâmetro um vetor, então a complexidade do algoritmo será em função de n, o tamanho do vetor. Por exemplo, suponha que o algoritmo consiste em uma iteração sobre os elementos do vetor, e que a cada passo da iteração seja executado um número fixo k de instruções. Como exemplo analizamos o algoritmo 1 que, dado um vetor v e o tamanho n deste vetor retorna o maior elemento deste vetor.

Algoritmo 1 (máximo)

1 funct máximo(v : array (t); n :N) : t ≡ 2 var i :N 3 max : t 4 end 5 begin 6 if n = 0 7 then error(”maximo chamada com vetor vazio”) 8 else 9 max← v[1]

10 for i← 2 to n step 1 do 11 if v[i] > max 12 then max← v[i] 13 fi 14 od 15 fi 16 result← max .

O caso do número de elementos n ser nulo caracteriza um erro de utilização da função máximo, que não é definida para vetores nulos. Nos casos normais de operação, a avaliação do tempo de execução pode ser realizada através de uma análise do tempo de execução, o que requer ter uma ideia do funcionamento interno dos computadores, e em particular dos microprocessadores:

• O teste da linha 6 que se executa em tempo constante k1.

• A atribuição de inicialização da linha 9, também executado em tempo constante k2.

• O laço das linhas 10 até 14 é executado n− 1 vezes, e realiza os seguintes passos:

– Atribui à variável de iteração i o valor 2, ou o valor i + 1. No pior caso, cada atribuição é realizada num tempo máximo constante k3 (independente de n).

– Realiza o teste da linha 11, em tempo constante k4.

– Se a condição do teste for verdadeiro, é realizada na linha 12 uma atribuição, que é realizada em tempo constante k5.

2.1 Dicas para avaliar a complexidade de um algoritmo. 4

Consequentemente, o tempo total de execução t satisfaz:

t ≤ k1 + k2 + (n− 1)× (k3 + k4 + k5) t ≤ n(k3 + k4 + k5) + (k1 + k2 − k3 − k4 − k5) t ≤ k × n, onde k é uma certa constante

Neste caso a complexidade temporal é k.n, uma constante multiplicada pelo tamanho do vetor, e digamos que a complexidade temporal é linear.

Em relação ao espaço ocupado por esta função, observamos que, além dos parâmetros, são usados apenas duas variáveis. Logo, a complexidade espacial também é linear.

Exerćıcio 1 Definir uma função que, dada uma matriz quadrada, e n o tamanho da matriz. Avaliar a com- plexidade temporal desta função.

2.1.2 Algoritmos recursivos

Para avaliar a complexidade de uma função escrita de forma recursiva, é preciso analizar quantas vezes a função deve-ser chamada para chegar ao resultado esperado, e quantas operações acarretam cada chamada.

Se um algoritmo tem como parâmetro uma lista, então a complexidade do algoritmo será uma função de n, o comprimento da lista. Por exemplo, consideramos o algoritmo 2 que, dado uma lista de números naturais, retorna a soma dos elementos da lista.

Algoritmo 2 (soma)

1 funct soma(l : listN) :N ≡ 2 begin 3 if l = () 4 then result← 0 5 else result← primeiro(l) + soma(resto(l)) 6 fi .

Cada chamada recursiva de soma diminui de um comprimento da lista passada em parâmetro, com a exceção do caso do parâmetro ser uma lista vazia, em qual caso o algoritmo termina. Se n é o comprimento inicial, então o número total de chamadas será n + 1. A cada chamada serão realizadas as seguintes operações:

• O teste da linha 3 é executado em tempo constante k1.

• Dependendo do resultado deste testo, são executados

– ou a atribuição da linha 4, que é realizada em tempo constante k2,

– ou a atribuição da linha 5, que, desconsiderando o tempo das chamadas recursivas, é calculado em tempo constante k3.

Logo, a complexidade temporal t deste algoritmo satisfaz:

t ≤ (n + 1)× k1 + k2 + n× k3 t ≤ n× (k1 + k3) + k1 + k2 t ≤ n× k, , onde k é uma constante.

O algoritmo tem uma chamada recursiva que diminui de 1 o tamanho da lista, então haverá n chamadas, e o algoritmo tem complexidade temporal linear.

2.2 Comparação de algoritmos 5

Para avaliar a quantidade de memória necessária, é preciso ter um entendimento ainda melhor de como funcionam os micro-processadores. Cada chamada da função é realizada colocando em uma porção da memória, chamada a pilha de execução, certas informações, incluindo os parâmetros da função chamada. No caso da função soma, vimos que podia haver n + 1 chamadas recursivas, cada uma dela tendo como parâmetro uma lista de tamanho decrescente. A somatória dos comprimentos das listas passadas em parâmetro é:

n + (n− 1) + (n− 2) + . . . + 1 + 0 = n∑

i=0

i

= n× n + 1

2 ≤ k × n2

Neste caso, a complexidade espacial é uma função quadrática do tamanho da entrada. Na prática, compiladores podem otimizar esse tipo de código e gerar programas com complexidade espacial inferior à calculada.

Exerćıcio 2 Seja um algoritmo recursivo com duas chamadas recursivas que diminuem em 1 o comprimento da lista. A cada chamada, é executado um número fixado de operações constantes. Quais são as complexidades temporal e espacial deste algoritmo.

2.1.3 Considerações

Geralmente, quando se avalia a complexidade de um algoritmo, a análise é feita de forma menos precisa. As razões desta simplificação são que, primeiro é muito trabalho trabalhar contabilizando cada instrução, e segundo o custo de executar cada instrução varia grandemente entre diferentes versões do código executável (fatores sendo as capacidades de otimização do compilador, o tipo de micro-processador utilizado, a freqüência do relógio cadenceando o micro-processador, e uma variedade de outras caracteŕısticas). Assim, considera-se que um bloco de execuções que se executam uma única vez é considerado como um custo unitário. O custo de executar um laço é considerado como sendo o custo de executar o bloco dentro do laço multiplicado pelo número de vezes que o bloco é executado. Assim, se temos c bloco de iterações aninhadas, e que cada bloco efetua um número de iterações dependendo de n, a complexidade temporal é aproximativamente nc.

Se temos c bloco de iterações aninhadas, e que cada bloco efetua um número de iterações dependendo de n, a complexidade temporal é aproximativamente nc.

2.2 Comparação de algoritmos

O tempo de execução de um programa depende de vários fatores: a velocidade do computador no qual está rodando, a qualidade do compilador que foi usado e, em alguns casos, a qualidade do algoritmo. Se n é o tamanho da entrada, as funções comumente encontradas em análise de programas são k× n (linear), n× log n, k×n2 (quadrática), k×n3 (cúbica), k1× ek2×n (exponencial). Essa ordem é a ordem de preferência: um custo tempo e/ou espaço de complexidade linear é muito melhor que um custo cúbico. Enquanto programadores, nosso escopo de trabalho é a qualidade dos algoritmos empregados no programa. Veremos que para um mesmo problema, existe vários algoritmos posśıveis, de complexidade diferentes. O bom programador deve saber projetar e/ou escolher o melhor algoritmo dispońıvel.

Para comparar dois algoritmos, deve se estudar a complexidade desses algoritmos. Supondo que já calcu- lamos as funções dando o custo espaço e tempo desse algoritmos. Para comparar essas funções, podemos por exemplo desenhar o gráfico delas. No caso geral, várias configurações são posśıveis. Seja F e G as duas funções de custo que queremos comparar:

• Se F é sempre inferior a G, ou seja, o gráfico de F fica sempre em baixo do gráfico de G, então a escolha para o algoritmo correspondente a F é óbvia.

3 Definições formais 6

• Se F as vezes é inferior a G, e vice-versa, e os gráficos de F e G se intersetam em um número infinito de pontos. Neste caso, consideramo que há empate, e a função custo não ajuda a escolher um algoritmo.

• Se F as vezes é G inferior a G, e vice-versa, e os gráficos de F e G se intersectam em um número finito de pontos. Portanto, a partir de um certo valor de n, F é sempre superior a G, ou é sempre inferior. Neste caso, consideramos melhor aquele algoritmo que é inferior ao outro para grandes valores de n.

Portanto, no caso geral, nem sempre podemos dizer que F (n) < G(n). A abordagem escolhida é de comparar as taxas de crescimentos destas funções e seu comportamento quando o tamanho da entrada é muito grande. Quando estudamos o comportamento do gráfico das funções consideradas, observamos que a taxa de crescimento é o fator mais importante para relacionar essas funções quando n é grande.

Por exemplo, se temos um algoritmo A que tem uma complexidade de CA(n) = 1000 × n2 e um algoritmo B com uma complexidade de CB(n) = 0, 1× n3, consideraremos que B é mais complexo que A. Uma primeira observação é que a análise de algoritmos assim como a estudamos só é útil para comparar algoritmos que manipulam grandes quantidades de dados.

Exerćıcio 3 A partir de qual valor de n, CA torna se inferior a CB ?

Em geral, quando temos um problema a resolver, queremos obter uma solução de complexidade menor posśıvel: é melhor ter um algoritmo de complexidade polinomial, que exponencial.

Exerćıcio 4 Para um determinado problema P , temos algoritmos a, b, c, e d com as seguintes complexidades Ca(n) = 100× n× log n, Cb(n) = 1000× n, Cc(n) = 4× n2 e Cd(n) = 10−5 × en. Classificar esses algoritmos do melhor até o pior, em termo de complexidade.

Um pouco de terminologia

A tabela seguinte recapitula os termos utilizado para qualificar a complexidade de um algoritmo em função de n, o tamanho de sua entrada.

constante um número constante de operações logaŕıtmico log n linear n quadrático n2

cúbico n3

polinomial nk, onde k é constante exponencial en

3 Definições formais

Quando estuda-se algoritmos, é importante poder estimar a complexidade destes. Se o algoritmo é complicado, deve se usar uma abordagem formal para provar qual é sua complexidade computacional.

3.1 Limite superior: a notação O

A notação mais comumente usadas para medir algoritmos é O, que da um limite superior da complexidade:

Definição 1 (Grande O) A função custo C(n) é O(F (n)) se existe constantes positivas c e n0 tais que

C(n) ≤ c.F (n) quando n ≥ n0.

3.2 Limite inferior: a notação Ω 7

A notação O(F (n)) diz que existe um ponto n0 tal que para todos os tamanhos de entrada n superiores a n0, o custo é inferior a algum múltiplo de F (n), ou seja, F (n) cresce mais rapidamente que C(n).

Por exemplo dizer que o espaço alocado pela execução de um algoritmo é O(n2), significa dizer que a quantidade de memória usada é no máximo uma função quadrática da entrada. É importante observar que, na notação O, os termos de menor peso e os fatores podem sempre ser eliminados; assim O(4 × n3 + 10 × n2) e O(n3) são sinônimos, mas o segundo termo é mais simples e deve ser utilizado.

Quando a complexidade de um algoritmo A é O(f(n)), é comum dizer simplesmente que A é O(f(n)), e neste caso, entende-se que é a complexidade temporal.

Observa que se uma função é O(n) então ela é também O(n2), mas a afirmação O(n) é mais precisa.

Exerćıcio 5 Responder as seguintes perguntas. Justificar.

1. n2 + n + 1 é O(1) ? O(n) ? O(n2) ? O(n3) ? O(n× log n) ?

2. As complexidades temporal e spacial do algoritmo 2 são O(n) ? são O(n2) ?

3. Para o algoritmo 2, a complexidade temporal é O(n) e a espacial é O(n2) ?

3.2 Limite inferior: a notação Ω

A notação Ω é usada para especificar o limite inferior da complexidade de um algoritmo:

Definição 2 (Grande Omega) C(n) = Ω(F (n)) se existe constantes positivas c e n0 tais que C(n) ≥ c.F (n) quando n ≥ n0.

Essa definição diz que, a partir de um certo valor n0, o custo C(n) é maior que F (n), multiplicado por um certo fator constante. Assim C(n) cresce mais rapidamente que F (n).

Um teorema importante de algoŕıtmica diz que, em um processador seqüêncial, o tempo de execução de qualquer algoritmo de ordenação é Ω(n log n). Isso quer dizer que não existe algoritmos seqüênciais de ordenação que tenham uma complexidade temporal inferior a n log n.

3.3 Complexidade exata: a notação Θ

A notação Θ é usada para especificar exatamente a complexidade de um algoritmo:

Definição 3 (Grande Theta) C(n) = Θ(F (n)) quando C(n) = O(F (n)) e C(n) = Ω(F (n)).

Se um algoritmo A é Θ(F (n)), ele é ao mesmo tempo O(F (n)) e Ω(F (n)). Portanto, sua complexidade cresce tão rapidamente quanto a função F (n). F é uma medição exata da taxa de evolução da complexidade do algoritmo A. Por exemplo, o algoritmo 1 é Θ(n).

Em muitas ocasiões, a notação O é empregada onde a notação Θ seria adequada. Observa que isso não caracteriza um erro, mais simplesmente uma imprecisão.

3.4 Limite superior estrito: a notação o

Enfim a notação o é usada para especificar que a complexidade de um algoritmo e inferior estritamente a uma certa função:

Definição 4 (Pequeno O) C(n) = o(F (n)) quando C(n) = O(F (n)) e C(n) 6= Ω(F (n)).

Exerćıcio 6 • Mostrar que se um algoritmo é o(F (n)), então ele é O(F (n)).

• Existe um algoritmo seqüêncial de ordenação que tenha uma complexidade o(n log n) ?

4 Exemplo: O problema da soma da maior subseqüência 8

4 Exemplo: O problema da soma da maior subseqüência

Problema 1 Seja uma seqüência finita de inteiros (possivelmente negativos) a1, a2, . . . an. Calcular o valor de∑j k=i ai. Se todos os inteiros são negativos, a maior subseqüência é a subseqüência vazia e a sua soma é 0.

Por exemplo, para a entrada−2,11, -4, 13,−5, 2 a resposta é 20, correspondendo a subseqüência do segundo ao quarto elemento. Para a entrada 1,−3,4, -2, -1, 6 a resposta é 7, correspondendo a subseqüência os quatro últimos itens.

4.1 Um algoritmo cúbico

O algoritmo 3 é o mais simples e direto que se pode imaginar. Consiste em fazer uma busca exaustiva de todas as posśıveis subseqüências. O tamanho da entrada deste algoritmo é n, a quantidade de elementos no vetor parâmetro.

Dois laços iteram sobre os limites de todas as subseqüências posśıveis linhas(linhas 7 e 8), O valor de cada subseqüência é computado (linhas 10 a 12. Se esse valor for superior a da soma máxima computado até agora, armazenada na variável SomaMáxima, a soma máxima é atualizada (linha 13) Enfim, a função retorna o valor computado (linha 16)

Algoritmo 3 (subseqüênciaSomaMáxima)

1 funct subseqüênciaSomaMáxima(v : array Z, n :N) : Z ≡ 2 var soma, somaMáxima : Z 3 i, j, k :N 4 end 5 begin 6 somaMáxima← v[1] 7 for i = 1 to n step 1 do 8 for j = i to n step 1 do 9 soma← 0

10 for k = i to j step 1 do 11 soma← soma+ v[k] 12 od 13 if soma > somaMáxima then somaMáxima← soma fi 14 od 15 od 16 result← somaMáxima 17 end .

O espaço alocado pela execução deste algoritmo é o custo de representação dos parâmetros mais as variáveis locais. Logo, o custo espaço é então O(1). Para avaliar a complexidade em termo de tempo deste algoritmo, precisamos avaliar quantas vezes cada instrução é executada. O algoritmo é basicamente composto de 3 laços aninhados. As instruções as mais frequentemente executadas e, portanto, o termo dominante no tempo de execução deste algoritmo, são as das linhas 10 a 12. O número de vezes que as expressões compondo este laço são executadas é

n∑ i=1

n∑ j=i

j∑ k=i

1 = n(n + 1)(n + 2)/6

= O(n3).

4.2 Um algoritmo quadrático 9

4.2 Um algoritmo quadrático

O algoritmo cúbico é muito simples porém muito ineficiente. O algoritmo 4 mostra um algoritmo quadrático resolvendo esse problema.

Algoritmo 4 (subseqüênciaSomaMáxima)

1 funct subseqüênciaSomaMáxima(v : array Z, n :N) : Z ≡ 2 var soma, somaMáxima : Z; i, j :N 3 end 4 begin 5 somaMáxima← v[1] 6 for i = 1 to n step 1 do 7 soma← 0 8 for j = i to n step 1 do 9 soma← soma+ v[k]

10 if soma > somaMáxima then somaMáxima← soma fi 11 od 12 od 13 result← somaMáxima 14 end .

Esse algoritmo só contém dois laços aninhados, e é O(n2) (quadrático).

4.3 Um algoritmo linear

O algoritmo 5 é mais eficiente ainda. A ideia deste algoritmo é de realizar uma única iteração. A cada passo da iteração, a variável SomaMáxima armazena a maior subseqüência do vetor entre os ı́ndices 0 e i-1, e a variável SomaSufixo mantém a maior soma de todos os sufixo deste subvetor. Quando todos os sufixos tem valor negativo, SomaSufixo é nulo.

Este algoritmo só contém um bloco de iteração, que enumera todos os valores de 0 até N-1. Em cada iteração, existe um número máximo de instruções que serão executadas que é independente de N , e que logo é constante. Conclúımos portanto que este algoritmo é O(n).

Algoritmo 5 (subseqüênciaSomaMáxima)

1 funct subseqüênciaSomaMáxima(v : array Z, n :N) : Z ≡ 2 var somaSufixo, somaMáxima : Z; i, j :N 3 end 4 begin 5 somaMáxima← v[1] 6 somaSufixo ← 0 7 for i = 1 to n step 1 do 8 if v[i] + somaSufixo > somaMáxima 9 somaSufixo ← somaSufixo + v[i]

10 somaMáxima← somaSufixo 11 elsif (v[i] > 0) 12 somaSufixo ← somaSufixo + v[i] 13 else 14 somaSufixo ← 0

4.3 Um algoritmo linear 10

15 fi 16 od 17 result← somaMáxima 18 end .

Exerćıcios

1. Quais são as diferentes notações apresentadas para definir e comparar a complexidade de algoritmos ? Dar a definição de cada uma dela.

2. Revisar os principais algoritmos de ordenação que você conhece e determina a complexidade de cada um utilizando notações formais.

3. Mostrar por que o número de vezes que as expressões do algoritmo 3 é n(n + 1)(n + 2)/6.

4. Suponha C1(n) = O(F (n)) e C2(n) = O(F (n)). Qual das relações seguintes é verdadeira ?

(a) C1(n) + C2(n) = O(F (n))

(b) C1(n)− C2(n) = O(F (n)) (c) C1(n)/C2(n) = O(1)

(d) C1(n) = O(C2(n))

5. Um algoritmo leva 0.5 ms para uma entrada de tamanho 100. Qual é o tamanho da entrada que pode ser resolvida em um minuto quando o algoritmo em tempo é:

(a) linear

(b) O(n log n)

(c) quadrático

(d) cúbico

6. Um algoritmo leva 0.5 ms para uma entrada de tamanho 100. Quanto tempo ele levará para terminar com uma entrada de tamanho 500 se sua complexidade em tempo é:

(a) linear

(b) O(n log n)

(c) quadrático

(d) cúbico

essa fita memo paça MESSA SUAS COMPLEXIDADE PARÇA
ótimo conteúdo, obrigado.
legal ... ideia para problemas de prova
Ta tirando meu sono isso aqui !!! Ciência da Computação 2012 !! Ta acabando !!
Esta é apenas uma pré-visualização
3 mostrados em 10 páginas