Tipos de Análise
● Dois tipos de Análise são comuns: Eficiência
em termos de tempo e eficiência em termos de espaço
● A análise de tempo é mais frequente na
Análise de Tempo
● Experimental: implementar o algoritmo,
executar sobre a massa de dados e medir os tempos
● Complexidade: Estuda o algoritmo em termos
gerais, prevê propriedades de comportamento e eficiência
Complexidade
● Útil para entender os algoritmos de forma geral ● Oferece uma ferramenta importante para a
escolha de algoritmos mais adequados para certos problemas
● Pode determinar a viabilidade de se investir em
Análise Experimental
● Sujeita a detalhes de implementação, e
variáveis além do algoritmo: compilador, s.o., máquina, etc
● Útil em casos que o tempo é um fator muito
crítico
Análise de Complexidade
● O que medir em uma análise de
complexidade?
● Tamanho da entrada
● Entrada (real, aleatória, perversa) ● Número de operações relevantes
● Normalmente o número de operações
Exemplo: bubble Sort
for ( int i=0;i<n-1;i++){ for(int j=i+1;j<n;j++){ if(a[i]>a[j]){ int aux=a[i]; a[i]=a[j]; a[j]=aux; } }
Análise de Complexidade
● Informações relevantes são as operações de troca
e de comparação (dão resultados diferentes dependendo da entrada)
● As operações das repetições permanecem
idênticas para qualquer entrada de tamanho n
● Deve-se considerar quantas informações
relevantes foram feitas, e não o tempo que estas operações demoram para ser executadas
Análise de Complexidade
● Interessa saber o tempo t(n) de um algoritmo
de entrada com tamanho n
● A medida do tamanho da entrada varia de
acordo com o problema
● Ordenação: número de elementos
● Alg. Sobre grafos: número de vértices e arestas ● Alg. Numéricos: nº de bits dos números
Análise de Complexidade
● Encontrar a exata função t(n) pode ser muito
complicado
● É possível encontrar, com relativa facilidade,
funções assintóticas para t(n)
● Duas são de especial interesse: Pior Caso e
Notação O
● Notação que permite expressar o tempo de um
algoritmo suprimindo detalhes
Notação O - Definição
● Uma função g(n) é O(f(n)) se existem duas
constantes c e k positivas tal que
● As constantes c e k são usadas para abstrair os
detalhes de implementação
Classes de Algoritmos
● O(1) – Constante. O tempo do algoritmo não é
afetado pelo tamanho da entrada
● O(log n) – Logarítmico. Programas ficam
levemente mais lentos com o crescimento de n
● O(n) – Linear. Tempo cresce linearmente em
Classes de Algoritmos
● O(n2) – Quadrático. Tempo aumenta seguindo um
polinômio de grau máximo 2 em relação ao valor de n
● O(nk) – Polinomial. Tempo aumenta de acordo com
um polinômio de grau máximo k em relação ao valor de n
● O(kn) – Exponencial. O valor de n é usado como
Exemplo
n logn n n² n³ 2^n 1 0 1 1 1 2 5 2,321928094 5 25 125 32 10 3,321928094 10 100 1000 1024 15 3,906890595 15 225 3375 32768 20 4,321928094 20 400 8000 1048576 25 4,643856189 25 625 15625 33554432 30 4,906890595 30 900 27000 1073741824Visualmente
0 200000000 400000000 600000000 800000000 1000000000 1200000000 logn n n² n³ 2^n t( n )Visualmente
5000 10000 15000 20000 25000 30000 35000 logn n n² n³ 2^n t( n )Visualmente
0 200 400 600 800 1000 1200 logn n n² n³ 2^n t( n )Operações com a Notação O
● f(n) = O(f(n))
● c.O(f(n))= O(f(n)) para c constante ● O(f(n))+O(g(n)) = O(max(f(n),g(n))) ● f(n).O(g(n))=O(f(n).g(n))
Exercício
● Usando as operações da notação O mostre
Exercício
● Usando as operações da notação O mostre
que: O(O(f(n)))=O(f(n))
● A prova vem da aplicação direta da primeira
operação
● O(O(f(n))) {removendo a notação} ● =O(f(n))
Exercício
● Usando as operações da notação O mostre
Exercício
● Usando as operações da notação O mostre
que: O(f(n)).O(g(n)) = O(f(n).g(n))
● O(f(n)).O(g(n)) = f(n).O(g(n)) {removendo O} ● f(n).O(g(n))= O(f(n).g(n)) {multiplicação}
● Obs: também pode ser provado por
Exercício
● Usando as operações mostradas para a
notação O mostre que
Exercício
● Usando as operações mostradas para a
notação O mostre que
● O(f(n))+O(f(n))=O(f(n))
● O(f(n))+O(f(n)) = f(n)+f(n) {removendo notação} ● f(n)+f(n) = 2.f(n)
● 2.f(n) = c.f(n) {2 é uma constante} ● c.f(n)= c.O(f(n)){inserindo notação}
Notação Ω
● Notação que permite expressar o tempo de um
algoritmo suprimindo detalhes
Notação Ω - Definição
● Uma função g(n) é Ω(f(n)) se existem duas
constantes c e k positivas tal que
● As constantes c e k são usadas para abstrair os
detalhes de implementação
Notação θ
● Usada para fornecer um comportamento
assintótico firme
● Dizemos que uma função g(n) é θ(f(n)) se ela é
O(f(n)) e Ω(f(n))
● Uma função g(n) é θ(f(n)) se existem três
constantes constantes c1, c2 e k positivas tal que
Relações de Recorrência
● Formulas usadas para capturar a dependência
no tempo de um algoritmo de sua execução em entradas menores
Relações de Recorrência
t(n)=t(n-1)+n = t(n-2) + (n-1)+n … =t(1) + 2 + 3 + … + (n-1) + n = 1 + 2 + 3 + … + (n-1) + n =n(n+1)/2 → O(N2)Relações de Recorrência
Relações de Recorrência
● t(n)= t(n/2)+1 para n>=2 e t(1)=1 t(n)=t(n/2)+1 =t(n/4)+ 1 +1 =t(n/8)+1+1+1 … =t(1)+ 1+1+1...+1Relações de Recorrência
● Assumindo que n = 2^k –> k= lg n
Relações de Recorrência
Relações de Recorrência
● t(n)=t(n/2)+n para n>=2 e t(1)=1 =t(n/4)+n/2+n =t(n/8)+n/4+n/2+n (progressão geométrica) ● s = a 1 /(1-q) s = 2n → O(n)Relações de recorrência
Relações de recorrência
● t(n)= 2t(n/2)+n para n>=2 e t(1)=0 =2(2t(n/4)+n/2)+n =4t(n/4)+ n + n =4(2t(n/8) +n/4) +n +n =8 t(n/8) +n +n +n = n(lg n)Relações de Recorrência
Relações de Recorrência
● t(n)=2t(n/2)+1 para n>=2 e t(1)=0 =2(2t(n/4)+1)+1 =4t(n/4)+2+1 =4(2t(n/8)+1)+2+1 =8t(n/8)+4+2+1 (progressão geométrica) s= a1(1-q^t)/(1-q), q→razão, t → nº termosRelações de Recorrência
● s= a1(1-q^t)/(1-q), q→razão, t → nº termos
=(n(1-(1/2)^t))/(1/2) = 2n – 2n(1/2)^t, t=lg2n +1 =2n – 2n(1/2)(1/2)^lg2n =2n – n/(2^lg2n) =2n – n/n =2n-1 → O(n)
Influência das constantes
● Em alguns casos é possível afirmar que a
análise assintótica não é adequada para comparar algoritmos em casos específicos
● Ex: sejam dois algoritmos “a” e “b” onde o
tempo de “a” é metade do de “b”, ou seja
2Ta(n)=Tb(n). Tanto “a” quanto “b” são O(n), portanto, ao analisar somente as funções
Influência das Constantes
● Mesmo em casos onde a análise assintótica
determina qual é o melhor algoritmo, as constantes podem influenciar
● Ex: sejam dois programas “a” e “b” com tempos
de execução dados por a(n)=100n e b(n)=n^2. Pela análise assintótica determina-se que a é mais eficiente. No entanto, observe que para n<100, b é mais eficiente.
Análise de Complexidade
● Quando não é possível expressar o tempo em
função de uma única variável, analisamos as duas variáveis separadamente
● Ou transformamos a segunda variável em uma
função da primeira