4. Cormen (2002)
“Qualquer procedimento computacional bem
definido que toma algum valor ou conjunto de
valores como entrada e produz algum valor ou
conjunto de valores como saída”
5.
6. Algoritmos
• Razões para estudar:
• Prática:
• Devemos conhecer um conjunto de algoritmos de diferentes
áreas;
• Devemos ser capazes de projetar novos algoritmos e analisar
suas eficiências;
• Teóricas:
• O estudo de algoritmos é a “pedra fundamental” da computação;
• Desenvolver habilidades analíticas.
8. Tipos importantes de
problemas
• Ordenação: reorganizar itens de uma estrutura seguindo
alguma ordem;
• Busca: encontrar um dado valor chave em um dado
conjunto de valores;
• Processamento de textos: buscar uma dada palavra em
um texto; avaliar similaridade entre cadeias de caracteres;
etc;
• Problemas em grafos: planejamento de rotas; caminho
mais curto; ordenação topológica;
9. Tipos importantes de
problemas
• Problemas combinatoriais: encontrar um objeto
combinatória (permutações, combinações ou
subconjuntos) que satisfaça certas restrições e tenha
certas prioridades (maximizar um valor ou minimizar um
custo);
• Problemas geométricos: envolve objetos geométricos
como pontos, linhas ou polígonos;
• Problemas numéricos: envolve objetos matemáticos de
natureza contínua: resolução de equações e sistemas de
equações; integrais definidas, etc.
10.
11.
12. Estratégias de projeto de
algoritmos
• Força bruta (brute force);
• Dividir para conquistar (divide and conquer);
• Diminuir e conquistar (decrease and conquer);
• Transformar e conquistar (transform and conquer);
• Compromisso tempo-espaço (space and time tradeoffs);
• Estratégia gulosa (greedy);
• Programação dinâmica (dynamic programming);
• Voltando atrás (bracktracing);
• Ramificar e limitar (branch and bound);
13. Análise de algoritmos
• Significa prever os recursos de que ele necessitará.
• Em geral memória, largura de banda de comunicação ou hardware de
computação são as preocupações principais, mas frequentemente é o
tempo de computação que se deseja medir (Cormen, 2012).
• Basicamente temos dois tipos de análise:
• De um algoritmo particular - calcular o custo de um algoritmo
na resolução de um problema específico;
• De uma classe de algoritmos - considerando um problema
específico, determinar o algoritmo de menor custo possível
para resolvê-lo.
16. Complexidade computacional?
• Termo criado por Juris Hartmanis e Richard Stearns (1965)
• Classificação de problemas de acordo com sua dificuldade
• Relação entre: tamanho do problema; o tempo e espaço
necessários para resolvê-lo;
• Fundamental para projetar e analisar algoritmos.
• Leitura complementar: https://pt.wikipedia.org/wiki/Complexidade_computacional
17. Complexidade computacional?
• Termo criado por Juris Hartmanis e Richard Stearns (1965)
• Classificação de problemas de acordo com sua dificuldade
• Relação entre: tamanho do problema; o tempo e espaço
necessários para resolvê-lo;
• Fundamental para projetar e analisar algoritmos.
• Leitura complementar: https://pt.wikipedia.org/wiki/Complexidade_computacional
18. Complexidade de
algoritmos
• Complexidade Espacial:
• Quantidade de recursos utilizados para resolver o
problema
• Complexidade Temporal:
• Quantidade de tempo utilizado, ou número de instruções
necessárias para resolver determinado problema
• Medida de complexidade
• Parâmetro: tamanho do problema
19. Exemplos
• Ordenar n números
• Multiplicar duas matrizes quadradas n x n (cada uma com
n2 elementos)
“Relação entre: tamanho do problema; o tempo e espaço
necessários para resolvê-lo”
21. Complexidade de
algoritmos
Espacial Temporal
Recursos (memória)
necessários
• Tempo
• Número de instruções
necessárias
• Perspectivas:
• Pior caso;
• Caso médio;
• Melhor caso.
Como analisar por essas perspectivas?
22. Melhor caso
• Menor tempo de execução para uma entrada de tamanho n
• É pouco usado, por ter aplicação em poucos casos
• Exemplo:
• Problema: encontrar um elemento em uma lista de n números
• Complexidade no melhor caso:
• Assume-se que o número estaria logo na topo da lista
T(n) = 1
(função T que determina a complexidade de tempo)
23. Pior caso
• Maior tempo de execução sobre entradas de tamanho n
• É mais fácil de se obter
• Exemplo:
• Problema: encontrar um elemento em uma lista de n números
• Complexidade no pior caso:
• Assume-se que, no pior caso, o número estaria no final da
lista
T(n) = n
24. Caso médio
• Média dos tempos de execução de todas as entradas de tamanho n, ou
baseado em probabilidade de determinada condição ocorrer
• É mais difícil de se determinar
• Exemplo:
• Problema: encontrar um elemento em uma lista de n números
• Complexidade no caso médio:
• Para encontrar o i-ésimo número são necessárias i comparações
com probabilidade pi de procurar pelo número. Dado por:
T(n) = 1 . p1 + 2 . p2 + 3 . p3 + … + n . pn
26. Análise dos casos
• Então, determine T(n) quando o tamanho da lista n for:
n
Melhor caso
T(n) = 1
Caso médio
T(n) = (n + 1) / 2
Pior caso
T(n) = n
10
100
10000
1000000
27. Análise dos casos
• Então, determine T(n) quando o tamanho da lista n for:
n
Melhor caso
T(n) = 1
Caso médio
T(n) = (n + 1) / 2
Pior caso
T(n) = n
10 1 5,5 10
100 1 50,5 100
10000 1 5000,5 10000
1000000 1 500000,5 1000000
29. Crescimento de funções
• Comportamento assintótico
• Quando n tem valor muito grande (n >> ∞)
• Termos inferiores e constantes multiplicativas
contribuem pouco na comparação e podem ser
descartados
• Exemplo:
• Algoritmo 1: f1(n) = 2n2 + 5n operações
• Algoritmo 2: f2(n) = 500n + 4000 operações
30. Crescimento de funções
• Comportamento assintótico
• Quando n tem valor muito grande (n >> ∞)
• Termos inferiores e constantes multiplicativas contribuem pouco na
comparação e podem ser descartados
• Exemplo:
• Algoritmo 1: f1(n) = 2n2 + 5n operações
• Algoritmo 2: f2(n) = 500n + 4000 operações
Como crescem f1 e f2 ?
Qual o algoritmo mais eficiente?
31. Notação assintótica
• Define limites para o crescimento assintótico das
funções;
• Preocupação principal:
• A maneira como o tempo de execução de um
algoritmo aumenta com o tamanho da entrada no
limite, à medida que o tamanho da entrada aumenta
indefinidamente (tendendo ao infinito).
32. A notação Ω (ômega)
• Oferece um limite inferior assintótico
• Definição: Sejam f e g duas funções com domínio X.
Dizemos que a função f é Ω(g(n)) sse
(∃c ∈ R+)(∃n0 ∈ X)(∀n ≥ n0)(c.|g(n)| ≤ |f(n)|)
33. Notação Ω
• Então uma função f(n) é Ω(g(n)) se existem duas
constantes positivas c e n0 tais que:
c . g(n) ≤ f(n), para todo n ≥ n0
34. A notação O (ômicron)
• Oferece um limite superior assintótico
• Definição: Sejam f e g duas funções de domínio X.
Dizemos que a função f é O(g(n)) sse
(∃c ∈ R+)(∃ n0 ∈ X)(∀ n ≥ n0) (|f(n)| ≤ c.|g(n)|)
35. Notação O
• Então uma função f(n) é O(g(n)) se existem duas
constantes positivas c e n0 tais que:
f(n) ≤ c . g(n), para todo n ≥ n0
36. Exemplos (Notação O)
• 3n + 2 = O(n), pois 3n + 2 ≤ 4n para todo n ≥ 2
• 1000n2 + 100n – 6 = O(n2), pois
• 1000n2 +100n – 6 ≤ 1001n2 para n ≥ 100
• f(n) = amnm+...+a1n+a0 => f(n) = O(nm)
37. A notação θ (theta)
• Oferece limites assintóticos inferior e superior
• Definição: Sejam f e g duas funções de domínio X.
Dizemos que a função f é θ(g(n)) sse
(∃c1, c2 ∈ R+)(∃n0 ∈ X)(∀ n ≥ n0) (c1.|g(n)| ≤ |f(n)| ≤ c2.|g(n)|)
38. Notação θ
• Então uma função f(n) é θ(g(n)) se existem constantes
positivas c1 e c2 e n0 tais que:
0 ≤ c1 . g(n) ≤ f(n) ≤ c2 . g(n) para todo n ≥ n0
49. Referências
• Notas de aula (prof. Valdísio Viana - UECE)
• Notas de aula (prof. José Maria - UFC)
• Algoritmos: Teoria e Prática - Cormen (3a. Edição -
Elsevier)
• Estrutura de dados: algoritmos, análise da complexidade
e implementações em Java e C/C++ - Ana Ascencio e
Graziela Araújo (Pearson)