Análise de Algoritmos - DECOM-UFOP

Propaganda
Análise de Algoritmos
Parte 3
Prof. Túlio Toffolo
http://www.toffolo.com.br
BCC202 – Aula 06
Algoritmos e Estruturas de Dados I
Como escolher o algoritmo mais
adequado para uma situação?
(continuação)
Exercício da última aula teórica
•  Obtenha a função de complexidade f(n) dos algoritmos abaixo.
Considere apenas as operações envolvendo as variáveis x e y.
Para cada algoritmo, responda:
•  Qual o valor da variável x ao final da execução do algoritmo?
•  O algoritmo é O(n2)? É Ω(n3)?
•  O algoritmo é Ө(n3)?
void exercicio1(int n) {
int i, j, x, y;
x = y = 0;
for (i = 1; i <= n; i++) {
for (j = i; j <= n; j++) x = x + 1;
for (j = 1; j < i; j++)
y = y + 1;
}
}
void exercicio2(int n) {
int i, j, k, x;
x = 0;
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++) for (k = 1; k <= j; k++) x = x + j + k;
x = i;
}
Perguntas?
Comportamento Assintótico de Funções
•  Nas aulas passadas aprendemos:
•  Como calcular a função de complexidade f(n).
Ø  Melhor caso x Caso médio x Pior caso
Ø  Qual a influência desta função em algoritmos
aplicados sobre problemas de tamanho pequeno?
Ø  E sobre problemas grandes?
Ø  Estuda-se o comportamento assintótico das funções
de custo. O que isto significa?
5
Qual a ordem de complexidade?
void MaxMin1(int* A, int n, int* pMax, int* pMin) { int i; *pMax = A[0]; *pMin = A[0]; for (i = 1; i < n; i++) { if (A[i] > *pMax)
*pMax = A[i]; 2*(n-1)
if (A[i] < *pMin) *pMin = A[i]; } } 6
Qual a ordem de complexidade?
void MaxMin2(int* A, int n, int* pMax, int* pMin) { int i; *pMax = A[0]; *pMin = A[0]; for (i = 1; i < n; i++) { if (A[i] > *pMax)
*pMax = A[i]; else if (A[i] < *pMin) 2*(n-1)
*pMin = A[i]; } } 7
Comportamento Assintótico de Funções
•  Nas aulas passadas também aprendemos:
•  Comportamento assintótico das função de
complexidade f(n).
Ø  Dominação Assintótica
Ø  Notação O
Ø  Notação Ω e Notação Ө.
8
Operações com a Notação O
9
Dominação Assintótica
•  f(n) domina assintoticamente g(n) se:
Ø  Existem duas constantes positivas c e m tais que,
para n ≥ m, temos |g(n)| ≤ c|f(n)|.
10
Notação O
•  O valor da constante m mostrado é o menor valor
possível, mas qualquer valor maior também é válido.
•  Definição: uma função g(n) é O(f(n)) se existem duas
constantes positivas c e m tais que g(n) ≤ c f(n), para
todo n ≥ m.
11
Notação Ω
•  Especifica um limite inferior para g(n).
•  Definição: Uma função g(n) é Ω(f(n)) se:
Ø  Existem duas constantes positivas c e m tais que,
para n ≥ m, temos |g(n)| ≥ c|f(n)|.
12
Notação Ө
•  Exemplo gráfico de dominação assintótica que ilustra a
notação Ө.
•  Especifica um limite assintótico firme para g(n).
Ø  Para ser Ө(f(n)), uma função deve ser ao mesmo tempo
O(f(n)) e Ω(f(n)).
13
Notação Ө
Ø  Para mostrar que g(n) = 3n3 + 2n2 é Ω(n3) basta fazer:
c = 1, e então 3n3 + 2n2 ≥ n3 para n ≥ 0.
Ø  Seja g(n) = n2 para n par (n ≥ 0)
g(n) = n para n ímpar (n ≥ 1).
Neste caso g(n) poderá ser:
Ω(n2), se considerarmos
apenas entradas pares
Ω(n), se considerarmos
apenas entradas ímpares
Se considerarmos qualquer entrada possível, então g(n) é Ω(n)
14
Perguntas....
•  n é O(n log n)? Esta afirmação é útil?
•  n3 é Ω(n)? Esta afirmação é útil?
•  n é O(n)?
•  n é Ω(n)?
•  n é Ө(n)?
•  n é Ө(n log n)?
15
Comparação de Programas
•  Um programa com tempo de execução O(n) é melhor
que outro com tempo O(n2).
•  Porém, as constantes de proporcionalidade podem
alterar esta consideração.
•  Exemplo: um programa leva 100n unidades de tempo
para ser executado e outro leva 2n2. Qual dos dois
programas é melhor?
•  Depende do tamanho do problema.
•  Para n < 50, o programa com tempo 2n2 é melhor do que o que
possui tempo 100n.
16
Principais Classes de Problemas
•  f(n) = O(1)
•  Algoritmos de complexidade O(1) são ditos de complexidade
constante.
•  Uso do algoritmo independe de n.
•  As instruções do algoritmo são executadas um número fixo de
vezes.
17
Principais Classes de Problemas
•  f(n) = O(log n)
•  Um algoritmo de complexidade O(log n) é dito ter complexidade
logarítmica.
•  Típico em algoritmos que transformam um problema em outros
menores.
•  Pode-se considerar o tempo de execução como menor que uma
constante grande.
•  Quando n é mil, log2n 10, quando n é 1 milhão, log2n 20.
•  Para dobrar log n temos que elever n ao quadrado….
•  A base do logaritmo muda pouco estes valores: quando n é 1
milhão, o log2n é 20 e o log10n é 6.
18
Principais Classes de Problemas
•  f(n) = O(n)
•  Um algoritmo de complexidade O(n) é dito ter complexidade
linear
•  Em geral, um pequeno trabalho é realizado sobre cada elemento
de entrada
•  É a melhor situação possível para um algoritmo que tem de
processar/produzir n elementos de entrada/saída.
•  Cada vez que n dobra de tamanho, o tempo de execução dobra.
19
Principais Classes de Problemas
•  f(n) = O(n log n)
•  Típico em algoritmos que quebram um problema em outros
menores, resolvem cada um deles independentemente e
juntando as soluções depois.
•  Quando n é 1 milhão, nlog2n é cerca de 20 milhões.
•  Quando n é 2 milhões, nlog2n é cerca de 42 milhões, pouco mais
do que o dobro.
20
Principais Classes de Problemas
•  f(n) = O(n2)
•  Um algoritmo de complexidade O(n2) é dito ter complexidade
quadrática.
•  Ocorrem quando os itens de dados são processados aos pares,
muitas vezes em um anel dentro de outro.
•  Quando n é mil, o número de operações é da ordem de 1 milhão.
•  Sempre que n dobra, o tempo de execução é multiplicado por 4.
•  Úteis para resolver problemas de tamanhos relativamente
pequenos.
21
Principais Classes de Problemas
•  f(n) = O(n3)
•  Um algoritmo de complexidade O(n3) é dito ter complexidade
cúbica.
•  Úteis apenas para resolver pequenos problemas.
•  Quando n é 100, o número de operações é da ordem de 1
milhão.
•  Sempre que n dobra, o tempo de execução fica multiplicado por
8.
22
Principais Classes de Problemas
•  f(n) = O(2n)
•  Um algoritmo de complexidade O(2n) é dito ter complexidade
exponencial.
•  Geralmente não são úteis sob o ponto de vista prático.
•  Ocorrem na solução de problemas quando se usa força bruta
para resolvê-los.
•  Quando n é 20, o tempo de execução é cerca de 1 milhão.
Quando n dobra, o tempo fica elevado ao quadrado.
23
Principais Classes de Problemas
•  f(n) = O(n!)
•  Um algoritmo de complexidade O(n!) é dito ter complexidade
exponencial, apesar de O(n!) ter comportamento muito pior do
que O(2n).
•  Geralmente ocorrem quando se usa força bruta para resolver o
problema.
•  n = 20 → 20! = 2.432.902.008.176.640.000, um número com 19
dígitos.
•  n = 40 → um número com 48 dígitos.
24
25
26
Algoritmo Polinomial
•  Algoritmo exponencial no tempo de execução tem função
de complexidade O(cn); c > 1.
•  Algoritmo polinomial no tempo de execução tem função
de complexidade O(p(n)), onde p(n) é um polinômio.
•  A distinção entre estes dois tipos de algoritmos torna-se
significativa quando o tamanho do problema a ser
resolvido cresce.
•  Por isso, os algoritmos polinomiais são muito mais úteis
na prática do que os exponenciais.
27
Quem vê, entende...
Mas é quem faz que aprende!
28
Exercício 1
•  Indique se as afirmativas a seguir são verdadeiras ou
falsas e justifique a sua resposta
•  É melhor um algoritmo que requer 2n passos do que um que
requer 10n10 passos.
•  2n+1 = O(2n).
•  f(n) = O(u(n)) e g(n) = O(v(n))
=> f(n) + g(n) = O(u(n) + v(n))
•  f(n) = O(u(n)) e g(n) = O(v(n))
=> f(n) - g(n) = O(u(n) - v(n))
29
Exercício 2
// Considere A, B e C vetores globais
void p1 (int n) {
int i, j, k;
for (i=0; i<n; i++)
for (j=0; j<n; j++) {
C[i][j]=0;
for (k=n-1; k>=0; k--)
C[i][j]=C[i][j]+A[i][k]*B[k][j];
}
}
•  Calcule a função de complexidade e a complexidade
assintótica de p1
30
Exercício 3
void p2 (int n)
{
int i, j, x, y;
x = y = 0;
for (i=1; i<=n; i++) {
for (j=i; j<=n; j++) x = x + 1;
for (j=1; j<i; j++)
y = y + 1;
}
}
void p3 (int n)
{
int i, j, x, y;
x = y = 0;
for (i=1; i<=n; i++) {
for (j=i; j<=n; j++) x = x + 1;
}
}
•  Calcule a função de complexidade e a complexidade
assintótica de p2 e p3. Qual é mais rápido?
31
Perguntas?
Download