You are on page 1of 33

Análise de Algoritmos

Wilson Rubens Galindo


ATENÇÃO!!!

Utilizarei a linguagem
PORTHON
Mistura de
Português com Python
Introdução
„ Preocupação com o tempo de execução do
algoritmo
„ Dois métodos:
„ Empírico (relacionado ao tempo de execução)
„ Analítico (através de expressões matemáticas)
„ Vantagens
„ Analítico independe de computador
„ Empírico é fácil de analisar
Função de Complexidade
„ Tempo
„ Registra a quantidade de tempo necessário
para executar um algoritmo para resolver um
determinado problema. (nosso foco)
„ Espaço
„ Neste caso, mede-se a quantidade de
memória necessária para executar um dado
algoritmo.
Método Analítico
„ Considerações:
„ Dados suficientemente grandes.
„ Comportamento assintótico
„ Não são consideradas constantes aditivas ou
multiplicativas na expressão matemática
obtida.
„ Objetivo: Obter estruturas simples.
Método Analítico
„ A execução é dividida em passos
„ Cada passo contém operações consideradas
constantes
„ Importância
„ Facilidade na comparação de tempos de
algoritmos diferentes com mesmo objetivo.
„ Determinação de limite assintótico para
determinados algoritmos.
Exemplo
„ Algoritmo que faz a soma de matrizes

a=[], b=[], c=[] 1

for i in range(0,n): c1 n

for j in range(0,n): c2 n

c[i][j]=a[i][j]+b[i][j] 1

Análise de custo: 1 + c1 * c2 * 1
=1+n*n
= n2
Exemplo 2
„ Algoritmo que faz o produto de matrizes

for i in range(0,n) c1 n
for j in range(0,n): c2 n
c[i][j]=0 1
for k in range(0,n): c3 n
c[i][j]=c[i][j] + a[i][j] * b[i][j] 1

Análise de custo: c1 * c2 * c3
=n*n*n
= n3
Análise do pior caso
„ Imagine um algoritmo que execute em tempo
n, onde n é o tamanho da entrada, a maioria
de suas entradas, mas para um determinado
tipo de n, o algoritmo é n10. Qual o custo do
algoritmo?
„ Resposta: n10

„ Por quê?

„ Análise de pior caso.


Análise de caso médio
„ Probabilístico
„ No pior caso é pouco eficiente mas utiliza
outros métodos que compensam sua
complexidade.
„ Ex:
„ Algoritmo1: 5000n2+160n3+100n4+1000n5

„ Algoritmo2: n5
Comportamento Assintótico
„ O comportamento assintótico de f(n)
representa o limite do custo quando n cresce.

„ Definição: Uma função f(n) domina


assintoticamente outra função g(n) se
existem duas constantes positivas c e m tais
que, para n ≥ m, temos

|g(n)| ≤ c.|f(n)|
Comportamento assintótico
„ Graficamente temos:

f, g
c . f(n)

g(n)

n
m
Comportamento Assintótico
„ Exemplo: Seja g(n) = n e f(n) = -n2, com n
pertencente a Z+.
„ Por definição, temos:
|g(n)| ≤ c.|f(n)|
| n | ≤ c . |- n2 |
n ≤ c . n2
„ Note que, fazendo c=1 e m=1, f(n) domina
assintoticamente g(n).
Comportamento Assintótico
„ Graficamente temos:
f, g |f(n)| = c . n2, com c=1

g(n) = n

n
m=1
Notação O
„ Definição:
„ Sejam f, h funções positivas de variável
inteiras.
„ Diz-se que f é O(h), escrevendo-se f = O(h),
quando existir uma constante c > 0 e um valor
inteiro n0, tal que:
„ n > n0 => f(n) ≤ c . h(n)
Classes de Comportamento Assintótico

„ As principais classes de problemas possuem as


seguintes funções de complexidade:
„ f(n)=O(1): São algoritmos de complexidade
constante. O uso desses algoritmos independem
do tamanho de n. Neste caso, as instruções do
algoritmo são executadas um número fixo de
vezes.
Classes de Comportamento Assintótico

„ f(n)=O(log n): São algoritmos de complexidade


logarítmica. Este tempo de execução ocorre
tipicamente em algoritmos que resolvem um
problema transformando-o em problemas
menores.
„ f(n)=O(n): São algoritmos de complexidade
linear. Em geral, um pequeno trabalho é
realizado sobre cada elemento de entrada.
Classes de Comportamento Assintótico

„ f(n)=O(n .log n): Este tempo de execução ocorre


tipicamente em algoritmos que resolvem um
problema quebrando-o em problemas menores,
resolvendo cada um deles independentemente e
depois junta-se as soluções.
„ f(n)=O(n2): São algoritmos de complexidade
quadrática. Geralmente isto ocorre quando há
processamento com um laço dentro do outro.
São úteis quando n é relativamente pequeno.
Classes de Comportamento Assintótico

„ f(n)=O(n3): São algoritmos de complexidade


cúbica. Úteis apenas para resolver pequenos
problemas.
„ f(n)=O(2n): São algoritmos de complexidade
exponencial. Tais algoritmos geralmente não são
úteis para resolver problemas do ponto de vista
prático. Ocorrem em problemas quando se usa
“força bruta” para resolvê-los.
Classes de Comportamento Assintótico

„ Sobre classes de comportamento assintótico


destacam-se:
„ f(n)=O(cn), c>1: Algoritmos com essa função de
complexidade são chamados de algoritmos
exponenciais no tempo de execução.
„ f(n)=O(p(n)), p(n) é um polinômio: Já algoritmos
cuja função de complexidade é um polinômio são
conhecidos por algoritmos polinomiais no tempo
de execução.
Classes de Comportamento Assintótico

„ Algoritmos Exponenciais
„ Quando o tamanho de n é grande, tornam-se
bastante ineficientes na prática;
„ São geralmente simples variações de pesquisa
exaustiva;
„ Problemas solucionados apenas por tais
algoritmos são considerados intratáveis, isto é,
não existe solução por algoritmo polinomial.
Classes de Comportamento Assintótico

„ Algoritmos Polinomiais
„ Quando o tamanho de n é grande, tornam-se
muito úteis na prática;
„ São geralmente obtidos através de um
entendimento mais profundo da estrutura do
problema;
„ Apresentam boa solução, isto é, um problema é
considerado bem resolvido quando existe um
algoritmo polinomial para resolvê-lo.
Comparação entre Funções de
Complexidade
Segundo Garey e Johnson (1979, pág. 7), temos:
Função
de n=10 n=20 n=30 n=40 n=50 n=60
Custo
n 10-5 s 2.10-5 s 3.10-5 s 4.10-5 s 5.10-5 s 6.10-5 s

n2 10-4 s 4.10-4 s 9.10-4 s 16.10-4 s 25.10-4 s 36.10-4 s

n3 10-3 s 8.10-3 s 27.10-3 s 64.10-3 s 125.10-3 s 216.10-3 s


n5 0,1 s 3,2 s 24,3 s 1,7 min 5,2 min 13 min
2n 10-3 s 1s 17,9 min 12,7 dias 35,7 anos 366 séc.
3n 59.10-3 s 58 min 6,5 anos 3855 séc. 108 séc. 1013 séc.

OBS.: Um algoritmo linear executa em 1s um milhão de operações.


Técnicas de Análise de Algoritmos
„ Determinar a ordem de tempo de execução
de um algoritmo (notação O) é em geral mais
simples do que encontrar a expressão
matemática exata da função de
complexidade.
Técnicas de Análise de Algoritmos
„ Tentando tornar mais simples a tarefa de
obter tal expressão matemática, Aho,
Hopcroft e Ullman (1983) enumeraram
alguns princípios a serem seguidos:
„ 1. Operação de atribuição, leitura ou escrita
são consideradas como O(1).
Exceções: Chamada de função em comando de
atribuição e atribuições que envolvem vetores de
tamanho arbitrariamente grandes.
Técnicas de Análise de Algoritmos
„ 2. O tempo de execução de uma seqüência
de comandos é determinado pelo maior tempo
de execução de qualquer comando dessa
seqüência (operação dominante).
„ 3. O tempo de execução de um comando de
decisão é composto pelo tempo de execução
dos comandos executados dentro do
comando condicional mais o tempo para
avaliar a condição, que é O(1).
Técnicas de Análise de Algoritmos

„ 4. O tempo para executar um laço é a soma do tempo


de execução do corpo do laço mais o tempo de avaliar
a condição de parada (geralmente é O(1)),
multiplicado pelo número de iterações do laço.
„ 5. Quando o algoritmo possui procedimentos não
recursivos, o tempo de execução de cada
procedimento deve ser computado separadamente
um a um, iniciando com os procedimentos que não
chamam outros procedimentos.
Técnicas de Análise de Algoritmos

„ 5. (Continuação) Depois, avalia-se os


procedimentos que chamam os procedimentos
que não chamam outros procedimentos,
utilizando os tempos dos procedimentos já
avaliados. Este processo é repetido até chegar
no algoritmo principal.
Técnicas de Análise de Algoritmos

„ 6. Quando o algoritmo possui procedimentos


recursivos, para cada procedimento é
associada uma função de complexidade f(n)
desconhecida, onde n mede o tamanho dos
argumentos para o procedimento. Outra
opção é determinar o número total de
chamadas recursivas, calcular a
complexidade de uma dessas chamadas
recursivas (sem considerar outras chamadas),
e efetuar esse produto.
notação Ω
„ Definição: Sejam f,h funções positivas de
variável inteiras. Diz-se que f é Ω(h),
escrevendo-se f = Ω(h), quando existir uma
constante c > 0 e um valor inteiro n0, tal que:
„ n > n0 => f(n) ≥ c . h(n)
notação θ
„ Definição: Sejam f,h funções positivas de
variável inteiras. Diz-se que f é θ(h),
escrevendo-se f = θ(h), quando ambas as
condições acontecem: f = O(h) e f = Ω(h).

You might also like