Sie sind auf Seite 1von 39

Análise de Algoritmos

Aula 3

Análise de complexidade da Busca Linear


Gisele Alves Santana
Resumo da aula
Nesta aula, você vai:
§ Conhecer os três principais tipos de casos
de análise de algoritmos:
• Melhor caso;
• Pior caso;
• Caso médio.
§ Entender a análise
amortizada e seus tipos.
Análise de algoritmos
Preocupa-se em medir e analisar os recursos
necessários por algoritmos para determinar
o tempo de sua execução.
A análise também estuda a viabilidade de um
algoritmo, fornecendo maneiras para se avaliar se o
mesmo é aplicável ao contexto a que ele se propõe.
Permite uma determinar a
viabilidade dos algoritmos,
através da medição de
sua complexidade.
Análise de algoritmos
Complexidade espacial
§ Mede a quantidade de memória que o algoritmo
requer para sua execução;
§ Produz uma função que relaciona o tamanho da
entrada com o espaço de armazenamento
requerido, como: e = g(n).
Análise de algoritmos
Complexidade temporal
§ Mede o tempo, considerando uma entrada
de dados, que o algoritmo requer para
produzir uma resposta;
§ Produz uma função que relaciona o tamanho da
entrada com o tempo de execução, como: t = f(n).
Análise de algoritmos
Considere uma função responsável por encontrar o
maior elemento de um vetor:
int maior_elemento(int vetor[], int n)
{
int i;
int maior = vetor[0];
for(i = 1; i < n; i++) {
if (vetor[i] > maior) {
maior = vetor[i];
}
}
return maior;
}
Análise de algoritmos
O comando de repetição “for” é executado, no
máximo, em um total de vezes igual ao tamanho do
vetor menos uma unidade, ou seja: n-1.
O comando de seleção “if” também é executado no
máximo na mesma quantidade de vezes.
int maior_elemento(int vetor[], int n) -
{ -
int i; -
int maior = vetor[0]; 1
for(i = 1; i < n; i++) { n-1
if (vetor[i] > maior) { n-1
maior = vetor[i]; A<n-1
} n-1
} n-1
return maior; 1
}
Análise de algoritmos
A análise de complexidade realizada em função de
“n”, onde n indica o tamanho da entrada, considera,
por exemplo: o número de elementos de um vetor,
número de vértices num grafo, número de linhas
de uma matriz etc.
Nesta análise, diferentes tamanhos de entradas
podem ter um custo diferente.
Três casos para medir a
complexidade de um algoritmo:
§ Melhor caso;
§ Pior caso;
§ Caso médio.
Melhor, pior e caso médio
Nessas análises são abstraídos o custo de cada
instrução, atribuindo uma constante ci
para representá-los.
A análise de algoritmos é responsável pela medição
da complexidade ou a quantidade de trabalho
necessária para a execução de um algoritmo.
Melhor, pior e caso médio
Pode-se expressar a quantidade de trabalho
através de operações fundamentais, que podem
variar de acordo com o algoritmo, e em função do
volume de dados.
As operações fundamentais ou primitivas são as
instruções que o processador executa, possuindo
um período de tempo fixo e finito.
Melhor, pior e caso médio
Exemplo: operação de busca sequencial de um
determinado elemento em um vetor.
Considerar a quantidade de posições do vetor que
deve ser processada no processo de busca
§ No melhor caso: apenas uma posição precisa ser
processada, pois o elemento desejado é
encontrado na primeira posição.
Melhor, pior e caso médio
Exemplo: operação de busca sequencial de um
determinado elemento em um vetor.
Considerar a quantidade de posições do vetor que
deve ser processada no processo de busca.
§ No pior caso: o elemento desejado é encontrado
apenas na última posição do vetor;
§ No caso médio: como o próprio
nome sugere, é realizada uma
média entre o melhor
e o pior caso.
Melhor, pior e caso médio
Assim, para essa situação de busca sequencial em um
vetor, tem-se que:
§ Melhor caso: f(n) = 1
§ Pior caso: f(n) = n
§ Caso médio: f(n) = (n+1)/2
Continuando...
Análise de complexidade
da Busca Linear
Pior caso
A análise de complexidade de algoritmos concentra-
se principalmente na identificação do pior caso.
O pior caso é uma garantia de que o algoritmo nunca
irá demorar mais do que esta estimativa.
Em algumas aplicações, o pior caso
acontece com muita frequência.
Por exemplo, o caso médio nas
buscas de informações em banco
de dados geralmente tendem a
ser tão ruins quanto o pior caso.
Pior caso
Para o cálculo do pior caso, deve-se determinar uma
entrada, de tamanho n, tal que a operação básica é
executada a maior quantidade de vezes possível.
Considere o código a seguir que realiza a busca linear
por um determinado elemento em um vetor.
int busca(int vetor[], int k, int tam) No pior caso, a quantidade de
{ vezes que a operação básica é
int i=0; executada é igual a: n + 1.
while ((vetor[i] != k) && (i < tam))
i = i + 1;
if (i <= tam)
return i;
else
return NULL;
}
Melhor caso
Como o próprio nome sugere, no melhor caso uma
operação de pesquisa por um elemento em uma
determinada estrutura de dados é completada assim
que a mesma se inicia.
Por exemplo, encontrar o elemento desejado
na primeira posição de um vetor.
Para o cálculo do melhor caso,
deve-se determinar uma entrada,
de tamanho n, tal que a operação
básica é executada a menor
quantidade de vezes possível.
Melhor caso
Para o cálculo do pior caso, deve-se determinar uma
entrada, de tamanho n, tal que a operação básica é
executada a maior quantidade de vezes possível.
Considere o código a seguir que realiza a busca linear
por um determinado elemento em um vetor.
Melhor caso
Busca linear por um determinado elemento
em um vetor.
int busca(int vetor[], int k, int tam) No melhor caso, k = vetor[0],
{ e o numero de vezes que a
int i=0; operação básica é executada
while ((vetor[i] != k) && (i < tam)) é igual a 1.
Ou seja, o valor procurado foi
i = i + 1;
encontrado na primeira
if (i <= tam) posição do vetor.
return i;
else
return NULL;
}
Caso médio
No caso em que o algoritmo possua partes que podem
ou não vir a ser executadas dependendo da entrada,
define-se uma nova variável de tempo de execução
auxiliar e utiliza-se esta variável na computação do
tempo final.
O cálculo do caso médio é realizado assumindo uma
distribuição probabilística das possíveis
entradas de tamanho n.
Assim, é realizada uma média
ponderada do custo para aquela
entrada com a probabilidade
correspondente.
Caso médio
int busca(int vetor[], int k, int tam) A probabilidade de “k”
{ estar armazenado em
int i=0; “vetor” é: 0 <= p <= 1;
while ((vetor[i] != k) && (i < tam)) A probabilidade de “k”
estar armazenado em
i = i + 1;
cada posição de
if (i <= tam) “vetor[i]” é: p/n;
return i;
else
return NULL;
}

O custo do algoritmo se “k” está armazenado


em “vetor[i]” é igual a: i.
O custo do algoritmo se “k” não está
armazenado em “vetor” é igual a: n+1.
Caso médio
Cálculo da complexidade média

Então:
Caso médio
CUSTO QNT VEZES
int busca(int vetor[], int x, int k) {
int i; c1 1
while ((i <= x) && (vetor[i] != k)) c2 n+1
i++; c3 n
if(i>b) c4 1
return -1; c5 1
else return i; c6 1
}

A variável “n” representa o número de vezes que a


instrução de incremento (i++) é executada.
A quantidade de elementos do vetor é determinada
pela variável “N”. O valor dessa variável depende do
número de vezes que o laço é executado.
Caso médio
Cálculo médio do tempo de execução
T(N) = c1+ c2(n+1) + c3.n + c4 + c5

No melhor caso:
§ T(N) = c1+ c2 + c4 + c5

No pior caso:
§ T(N) = c1+ c2(N+1) +
c3.N + c4 + c5
Finalizando...
Análise de complexidade
da Busca Linear
Análise amortizada
Consiste em uma nova técnica de análise, que auxilia
no estudo do tempo necessário para se efetuar uma
sequência de operações.
Principal objetivo: determinar o custo médio
por operação, não necessitando de uma
distribuição probabilística.
Análise amortizada
Considera o custo médio de cada operação no pior
caso e não somente uma analise de caso médio.
Métodos de resolução:
§ Análise agregada;
§ Análise do contador;
§ Análise do potencial.
Análise agregada

Princípio: mostrar que para qualquer n, uma


sequência de n operações é executada no pior
caso em tempo T(n).
Assim, o custo amortizado por operação
e T(n) são iguais a n.
A análise agregada considera que todas as
operações têm o mesmo custo amortizado.
Análise agregada
Como exemplo, considere uma estrutura do tipo
pilha, que possua as operações de empilhamento
(Push), desempilhamento (Pop) e verificação de
pilha vazia (IsEmpty).
Suponha que cada uma dessas operações é executada
em um tempo constante (foi adotado o tempo 1).
Análise agregada
Considere a operação “MultiPop” que desempilha os x
primeiros elementos da pilha, deixando-a vazia caso
contenha menos de x elementos.
MultiPop(S, x) {
while ((! IsEmpty(S)) && (x != 0))
Pop(S);
x = x-1;
}
Análise agregada
Em cada iteração é executada uma operação
“Pop” em tempo 1.
Assim, o custo dessa função é igual a: min(s; x).
Suponha uma sequência de n operações Pop, Push e
MultiPop sobre uma pilha vazia.
Como o tamanho da pilha é no máximo n, então
uma operação MultiPop é executada no
pior caso em tempo O(n).
Qualquer operação na sequência
é executada no pior caso em O(n)
e a sequência executa
em tempo O(n2).
Análise agregada
Com a análise agregada é possível a obtenção de um
limite mais apertado para o tempo de execução de
uma sequência de n operações (Push, Pop, e MultiPop).
Cada elemento é desempilhado no máximo uma vez
por cada operação de empilhamento. Na sequência, a
operação “Pop” pode ser chamada no máximo a
mesma quantidade de vezes que a operação “Push”.
O custo de execução da sequência
é <= 2n (1 unidade de tempo para
cada operação de empilhamento
e desempilhamento), ou seja, O(n).
Análise agregada
Custo médio ou custo amortizado de cada operação:
§ O(n) / n = O(1)

Custo amortizado:
§ O(1)
Análise contabilística
Nesta análise, são atribuídos custos amortizados ci
possivelmente diferentes às várias operações.
Se o custo amortizado total de uma sequência de n
operações for um limite superior para o custo real,
então o custo total amortizado fornece um limite
para o tempo de pior caso da sequência.
Isso significa que os custos
amortizados individuais de
cada operação podem ser
considerados válidos para
efeitos de análise de pior caso.
Análise contabilística
Uma forma de se garantir essa condição é assegurar
que em qualquer momento na execução da sequência
de operações, o custo acumulado deve ser sempre
não-negativo.
Por exemplo:
Análise do potencial
Enquanto a análise contabilística gera crédito
individualmente por cada operação realizada, a
análise potencial considera esse credito de maneira
global, com base em uma função de potencial sobre os
estados sucessivos de determinada estrutura de dados.
Suponha que i seja o potencial de uma estrutura de
dados no estado i (depois de i operações da sequência).
O custo amortizado da operação
i pode ser dado por:
Análise do potencial
A ideia principal é que o potencial da estrutura deve
aumentar com operações de baixo custo e diminuir
com operações de alto custo.
O cálculo do custo amortizado total é dado por:
Análise do potencial
Seguindo com o exemplo da pilha, suponha que Φi
seja o número total de elementos armazenados na
mesma depois de i operações.
Assim, tem-se que: Φ0 = 0 e Φi >= 0 para i > 0.