Transcript Estruturas de Dados – aulas – bloco 4
UNDB ESTRUTURAS DE DADOS Prof. Alessandro Gonçalves
Complexidade de Algoritmos
Conceituação Complexidade no pior caso, melhor caso e caso médio Exemplos
Complexidade de Algoritmos
Avaliação de tempo na história: 1) Algoritmos primitivos 2) A avaliação do tempo na matemática.
–
Ex: tábuas de Log 3) O aparecimento do computador
–
O tempo como fator primordial
Complexidade de Algoritmos
Avaliação de espaço na história: 1) No início era fundamental
–
Ex: quanto de memória tenho ?
–
Eniac: 200 bits 2) Hoje já não é tão importante
–
Era da fartura
Complexidade de Algoritmos
Dois métodos para avaliar o tempo: Empírico e Analítico Empírico 1) Medição do tempo de execução do algoritmo 2) Dependentes do hardware (memória, computador...) e software (compilador, linguagem...) 3) Permitem tratamento estatístico 4) Mais simples de ser implementado
Complexidade de Algoritmos
Dois métodos para avaliar o tempo: Empírico e Analítico Analítico 1) Expressões matemáticas para determinar o tempo 2) Independentes do hardware (memória, computador...) e software (compilador, linguagem...) 3) Permitem tratamento estatístico 4) Mais complexo de ser implantado
Complexidade de Algoritmos
Implantação do método Analítico 1) Considera-se grande quantidade de dados 2) Valores assintóticos 3) Desconsiderar constantes aditivas e multiplicativas
–
Ex: 2*n² + 10x + 5 é equivalente a n² + x.
–
As duas expressões acima são da ordem n² 4) Baseado em uma variável independente, na entrada do algoritmo(caixa preta) 5) Mais complexo de ser implantado
Complexidade de Algoritmos
Definindo uma expressão matemática 1) Divide-se o algoritmo em passos 2) Cada passo é composto de número fixo de operações básicas 3) A operação básica de maior frequência é conhecida como “operação dominante”.
4) O número de passos do algoritmo é a frequência da operação dominante.
5) Em algoritmos de ordenação, geralmente a operação dominante é a comparação.
Complexidade de Algoritmos
Exemplo em C – inverte.c
Resumo: void inverte() { int x, temp; } } for (x = 0; x<5; x++) { temp = vet[x]; vet[x] = vet[9-x]; vet[9-x] = temp; Cada passo corresponde a troca entre dois elementos Variável independente: número de elementos (n) Número de passos: número de execuções do bloco
Complexidade de Algoritmos
2 3 5 0 1 2 3 0 1 Soma de matrizes (para a turma resolver) 0 0 2 3 -1 4 -4 1 0 2 3 7 3 0 6 -1 1 1 Algoritmo: Para i = 1 até n faça Para j = 1 até n faça Cij = Aij + Bij Fim Para J Fim Para i Variável independente ?
Número de passos ?
Número de linhas da matriz N²
Complexidade de Algoritmos
25 9 36 8 Multiplicação de matrizes (para a turma resolver) 2 7 69 47 4 3 5 2 70 55 Algoritmo: Para i = 1 até n faça Para j = 1 até n faça Dij = 0 Para k = 1 até n faça ...
Dij = Dij + Aik * Bkj
Número de colunas da matriz A
Número de passos ?
N³
Complexidade de Algoritmos
Definindo uma expressão matemática Nos exemplos anteriores, o número de passos dependia sempre do tamanho da entrada, não do seu valor.
Mas isso nem sempre ocorre. Em geral, o número de passos depende do valor da entrada.
Considere: Duas matrizes A e B e uma variável X.
Se X = 0, faça C = A+B Se X <>0, faça D = A.B
Número de passos ?
N² ou N³
Complexidade de Algoritmos
Definindo uma expressão matemática para Complexidade de Tempo Ideal seria sempre conhecer o número de passos, conforme a entrada Difícil de ser atingido na prática Alternativa: determinar o número de passos para entradas específicas e representativas
Complexidade de Algoritmos
Determinando entradas representativas A = Algoritmo E = {E1, E2..., En} T1 = número de passos de A, quando a entrada for Ei
Complexidade de Algoritmos
Complexidade do Pior Caso Número de passos da entrada mais desfavorável A mais utilizada Quase sempre é relevante(Ex: aplicações de segurança) Quando falo que um algoritmo tem uma Complexidade “X”, estamos falando da Complexidade do Pior Caso Complexidade do Melhor Caso Número de passos da entrada mais favorável Pouco utilizada Pouco relevante Aplicações específicas Complexidade do Caso Médio Número de passos da entrada média Relevante Tratamento matemático e geralmente, complexo pois depende da probabilidade
Complexidade de Algoritmos
q = 0.5 ou 50%
Complexidade de Algoritmos
Exercícios (20 minutos) 1) Calcule a complexidade do algoritmo para calcular n!
2) Sejam duas matrizes: (a ij ) e (b kj ) tais que: 1 < i < n; 1 <= k<= n; 1<= j <= m, escrever os algoritmos para fazer C = A + B D = A * B Determinar as complexidades
Complexidade de Algoritmos
Solução dos exercícios Soma := 0 Para i = n até 1 passo -2 faça Soma := Soma + n*(n-1); Fim Para Complexidade: n
Complexidade de Algoritmos
Solução dos exercícios Algoritmo: soma de matrizes Para i := 1 até n faça Para j := 1 até p faça Cij := aij + bij Complexidade = n.p
Complexidade de Algoritmos
Solução dos exercícios Algoritmo: multiplicação de matrizes Para i := 1 até n faça (linhas da matriz A) Para j := 1 até p faça (colunas da matriz B) Dij = 0 Para k := 1 até p faça Dij := Dij + aik * bkj Complexidade = n.p.k
Complexidade de Algoritmos
Análise de algoritmo Demo (A,n) { Entrada: um array A[] com n elementos inteiros Saída: o maior elemento em A[];
Int c; C = A[0]; For (i = 1; i < n; i ++) { If (c < A[i]) c = A[i]; } } Return c;
Quantas operações primitivas são necessárias para a execução ?
Complexidade de Algoritmos
Análise de algoritmo 1) inicializar a variável array como A[0]. Duas operações primitivas 2) o contador i é inicializado com o valor 1 no início do laço for. Corresponde a uma operação primitiva 3) a condição i < n é verificada antes de entrar no laço for. Uma operação primitiva de comparar dois números; 4) o contador i é inicializado em 0 e incrementado em 1 no fim de cada iteração do laço, a comparação i < n é feita n vezes, assim a condição contribui com n unidades para a contagem
Complexidade de Algoritmos
Análise de algoritmo 5) o laço for é executado n-1 vezes. A cada iteração, A[i] é comparado com c (duas operações primitivas indexação e atribuição). O contador i é incrementado. Duas operações primitivas, soma e atribuição. Assim, a cada iteração do laço quatro ou seis operações são realizadas, dependendo se A[i] < c ou A[i] > c. Desta forma, o corpo do laço contribui para a contagem variando de 4(n-1) ou 6(n-1) 6) retorna o valor da variável que corresponde a uma operação primitiva e é executada apenas uma vez.
Resumo Melhor caso: 2 + 1 + n + 4(n-1) + 1 = 5n Pior caso: 2 + 1 + n + 6(n-1) + 1 = 7n - 2
Complexidade de Algoritmos
Notação O (Omicron) Refere-se ao pior caso Melhor caso: 2 + 1 + n + 4(n-1) + 1 = 5n => n Pior caso: 2 + 1 + n + 6(n-1) + 1 = 7n – 2 => n O(n) = f(x) = 7n -2 Para calcularmos O, consideramos sempre o valor mais relevante, em termos de “n” ou outras variáveis envolvidas
Complexidade de Algoritmos
Exercícios 1) n³ -1 2) n² + 2.log n n n 3) 3.n + 5.2
n n - 1 4) (n-1) + n n n² 5) 5.3 + 4.2
6) 6.347.562
7 n 7) 5.n + 3.2 + n!
8) 3n + 7m + 2 9) 5n² + 9m + 4 10) 3n + 5m + n.m
Complexidade de Algoritmos
Respostas 1) O(n³) 2) O(n²) n 3) O(n) n 4) O(n) n ² 5) O(2) 6) O(1) 7) O(n!) 8) O(n + m) 9) O(n² + m) 10) O(n.m)
Complexidade de Algoritmos
Escalas N 1 10 100 log 0 2 3.32
6.64
n n 1 10 100 1000 9.97
n!
2 n O(n) 1000 n.log
2 n 0 33 664 9970 n² n² 1 100 10.000
1.000.000
n.log
2 n n³ 1 1000 1.000.000
10 9 n 2 n 2 1024 1,28 x 10 30 1,072 x 10 31 n!
1 3x10 6 3x10 157 3x10 2567 n log 2 n
Complexidade de Algoritmos
Propriedades da notação O O(g + h) = O(g) + O(h) O(g . h) = O(g) . O(h) O(k . g) = k . O(g) = O(g)
Complexidade de Algoritmos
Video Torre de Hanoi Programa Torre de Hanoi em C Para solucionar um Hanói de 64 discos, são necessários 18.446.744.073.709.551.615 movimentos
Complexidade de Algoritmos
Propriedades da notação O Cota superior – menor complexidade de um algoritmo conhecido Nos exemplos anteriores, a complexidade de multiplicação de matrizes era O(n³) O(n³) O algoritmo de Strassen diminuiu a complexidade para O(n 2,807 ) O(n 2,807 ) O(n³) O algoritmo de Coppersmith e Winograd melhoraram para O (n 2,376 ) O (n 2,376 ) O(n 2,807 ) O(n³)
Complexidade de Algoritmos
Notação Ɵ (Teta) Refere-se ao caso médio Este é o caso que é o mais difícil de ser determinado, pois, necessita de análise estatística e em conseqüência de muitos testes, contudo é muito utilizado, pois é o que representa mais corretamente a complexidade do algoritmo.
Exemplo : Procurar uma palavra em um busca de uma palavra na metade do dicionário. Pode-se iniciar a dicionário. Imediatamente se sabe se foi encontrada a palavra ou, no caso duas metades deve se repetir o processo contrário, em qual das (é um processo recursivo) até se chegar ao resultado. Em cada busca (ou sub-busca), o problema (as reduzindo páginas em que a palavra pode estar) vão se à metade, o que corresponde com a função logarítmica.
Este procedimento de busca (conhecido como busca uma estrutura ordenada têm complexidade logarítmica.
binária) em Ɵ(log 2 n)
Complexidade de Algoritmos
Notação Ω (ômega) Refere-se ao melhor caso Pouco utilizado porque sempre precisamos saber como o algoritmo se comporta em situações difíceis (pior caso).
Exemplo : Exemplo 1: Em uma lista telefônica queremos encontrar um número, assume-se que a complexidade do caso melhor é Ω (1), pois está pressupondo-se o número desejado está na primeira posição.
Exemplo 2: Extrair qualquer elemento de um vetor. A se queira buscar. Portanto constante Ω (1).
indexação em um vetor ou array, leva o mesmo tempo seja qual for o índice que é uma operação de complexidade
Complexidade de Algoritmos
Conclusão Nas complexidades algorítmicas temos: Ω( ) <= θ( ) <= O() Algoritmos ótimos podem ser obtidos de duas formas: 1) melhoramento interno do código OU 2) comparação dos algoritmos entre si, escolhendo o de menor complexidade.
exemplo
Complexidade de Algoritmos
UNDB
ESTRUTURAS DE DADOS Prof. Alessandro Gonçalves [email protected]