240 likes | 378 Views
Algoritmos e Estrutura de Dados: Uma pequena motivação. Luiz Gonzaga da Silveira Jr lgonzaga@unisinos.br. Cenário visionário. Suponha que os computadores fossem infinitamente rápidos, com memória infinita. Você precisaria estudar algoritmos?! Me dê 2 razões...
E N D
Algoritmos e Estrutura de Dados: Uma pequena motivação Luiz Gonzaga da Silveira Jr lgonzaga@unisinos.br
Cenário visionário • Suponha que os computadores fossem infinitamente rápidos, com memória infinita. Você precisaria estudar algoritmos?! • Me dê 2 razões... • Demonstrar que o método de sua solução termina, e, • o faz com a resposta correta! • Se todos os métodos estivessem corretos, você escolheria o método mais fácil de implementar... • Mas o mundo perfeito não existe: velocidade infinita e memória grátis...
Eficiência: Caso • Computador A: 1 bilhão de instruções/sec • Computador B: 10 milhões de instruções/sec • Conclusão: • CompA é 100x mais rápido do que CompB • Programador mais ansioso do mundo: • Ordenação (inserção) 2n2 instruções para ordenar n números no CompA • Programador mais relaxado do mundo: • Ordenação (intercalação) 50 n log n instruções para ordenar n números no CompB • Para ordenar 01 milhão de números: • CompA: ~2000 segundos • CompB: ~100 segundos • CompB executou 20x mais rápido do que o CompA
Alguns problemas • Ordenação • Busca • Armazenamento • Compressão • Transmissão • Descompressão Parâmetros de qualidade • Corretude (depuração) • Desempenho (perfilação)
Ordenação • Ordenar buscar! • Exercício 1:Uma função que verifique se um vetor v[0..n-1] está em ordem crescente. • Exercício 2:Uma função que busque a ocorrência de um valor em um vetor v[0..n-1] • Exercício 3:Uma função que ordene um vetor com N elementos. • Comparaçãohttp://cg.scs.carleton.ca/~morin/misc/sortalg/
Qual a complexidade destas funções para as soluções encontradas?! • Melhor caso? • Pior caso? • Caso médio?
Um pouco de noção de complexidade • Ao ver uma expressão como n+10 ou n2+1, a maioria das pessoas pensa automaticamente em valores pequenos de n, valores próximos de zero. • Testar: para n=2, n=3,n=4, n=10, n=100 • A análise de algoritmos faz exatamente o contrário: ignora os valores pequenos e concentra-se nos valores enormes de n.
Algumas funções • Observemos as seguintes funções:n2 , (3/2)n2,9999n2, n2/1000, n2+100n • Quem cresce mais rápido?! (claro, para valores enormes de n): vamos experimentar! • Resposta: • Todas têm crescimentos equivalentes • Crescimento assintótico! • Nessa “matemática”, as funções são classificadas em ORDENS. • Funções de mesma ordem são ditas equivalentes. • As funções acima pertencem a mesma ordem
Ordem O (Big-Oh) • Segundo Knuth, “O” trata-se do ômicron grego maiúsculo. • Definição: Dadas funções assintoticamente não-negativas f e g, dizemos que f está na ordem O de g, e escrevemos f = O(g), se f(n) ≤ c · g(n) para algum c positivo e para todo n suficientemente grande. • Em outras palavras, existe um número positivo c e um número N tais que f(n) ≤ c · g(n) para todo n maior que N. • Exemplo: Se f(n) ≤ 9999 g(n) para todo n ≥ 1000 então f = O(g). (Mas cuidado: a recíproca não é verdadeira!)
Exemplo • Dadas as funções: f(n) = (3/2)n2 + (7/2)n – 4 e que g(n) = n2. n f(n) g(n) 0 –4 0 1 1 1 2 9 4 3 20 9 4 34 16 5 51 25 6 71 36 7 94 49 8 120 64 • A tabela sugere que f(n) ≤ 2g(n) para n ≥ 6 e portanto parece que f(n) = O(g(n)).
Bubblesort: intuitivo, porém...! bubbleSort( A : lista ) do swapped := false for each i in 0 to length( A ) - 2 do: if A[ i ] > A[ i + 1 ] then swap( A[ i ], A[ i + 1 ] ) swapped := true end ifend forwhile swapped end
Implementação Alternativa bubbleSort( A : lista ) n := length( A ) - 1 do swapped := false n := n - 1 for eachiin 0 tondo: if A[ i ] > A[ i + 1 ] then swap( A[ i ], A[ i + 1 ] ) swapped := true endif end for whileswapped end Qual a diferença entre as duas implementações?
Análise de complexidade • Para uma lista de n elementos • Pior caso: O(n2) • Melhor caso: O(n) • Posição dos elementos na lista define eficiência do algoritmo • Para grande quantidade de dados: ineficiente! • Na prática: • Simples (entender e implementar) • Aceitável para n pequeno!
5 2 4 6 1 3 2 5 4 6 1 3 2 4 5 6 1 3 2 4 5 6 1 3 1 2 4 5 6 3 1 2 3 4 5 6 Inserção • Analogia: cartas do baralho! • Funcionamento: mão esquerda vazia...cartas pra baixo, retira carta da mesa e vai inserindo • Complexidade • Melhor caso:O(n)! • Pior caso:O(n2)
Implementação void insercao (int n, int v[]) { int j, i, x; for (j = 1; j < n; j++) { x = v[j]; for (i = j-1; i >= 0 && v[i] > x; --i) v[i+1] = v[i]; v[i+1] = x; } }
Algoritmo de seleção void selecao (int n, int v[ ]) { int i, j, min, x; for (i = 0; i < n-1; ++i) { min = i; for (j = i+1; j < n; ++j) if (v[j] < v[min]) min = j; x = v[i]; v[i] = v[min]; v[min] = x; } } Ele seleciona o menor elemento do vetor, depois o segundo menor, e assim por diante Complexidade: O(n2)
Quicksort • Inventado por C.A.R. Hoare , em 1962. • Estratégia: dividir e conquistar! • Idéia: Dividir a lista em 2 sublistas • Atividade: • Pesquisar o funcionamento do algoritmo! • Implementar para um conjunto de valores inteiros contidos no site • Medir tempo!
Complexidade na prática • Considerações: • Tamanho do conjunto • Considerar usar algoritmos mais eficientes para grandes conjuntos • Natureza dos dados (repetidos, já ordenados ou praticamente ordenados,…) • Se 2 algoritmos tem mesma complexidade, qual utilizar?!
Problema • Determinar se um dado número está ou não está em um dado vetor ordenado. • Mais precisamente, dado um número x e um vetor crescente v[0..n-1], encontrar um índice m tal que v[m] == x. • É claro que o problema pode não ter solução. Este é o caso, por exemplo, se o vetor é vazio, ou seja, se n vale 0. • Ex:
Solução 1: óbvia e lenta • Comecemos com um algoritmo simples e óbvio: A função abaixo recebe um número x e um vetor // crescente v[0..n-1]. Ela devolve um índice m // em 0..n-1 tal que v[m] == x. • Se tal m não existe, // a função devolve -1. int buscaSequencial (int x, int n, int v[]) { int m = 0; while (m < n && v[m] < x) ++m; if (m < n && v[m] == x) return m; else return -1; }
Busca seqüencial • Comecemos com um algoritmo simples e óbvio: • // A função recebe um número x e um vetor // crescente v[0..n-1]. • Ela devolve um índice m tal que v[m] == x. • Se tal m não existe, a função devolve -1. • int buscaSequencial (int x, int n, int v[]) • { • int m = 0; • while (m < n && v[m] < x) • ++m; • if (m < n && v[m] == x) • return m; • else return -1; • }
Busca binária int buscaBinaria (int x, int n, int v[]) { int e, m, d; e = 0; d = n-1; while (e <= d) { m = (e + d)/2; if (v[m] == x) return m; if (v[m] < x) e = m + 1; else d = m - 1; } return -1; } Condição: Vetor ordenado! Info importante Diminuição o espaço de busca!
Falamos sobre estruturas… • Listas, vetores…indistintamente • Qual o papel destas estruturas nos processos de ordenação e busca?! Java: Vector, ArrayList, LinkedList,…