terça-feira, 14 de julho de 2015

Complexidade Computacional

Olá Pessoal,

Como eu tenho uma prova sobre complexidade computacional, o post de hoje será sobre isso.
Servirá, no meu caso, para rever o conteúdo, espero que de alguma forma possa ajudá-los também.  

O material utilizado para a elaboração deste post é de anotações em sala de aula, pesquisas (segue ao final do post alguns links) e livros (também ao final do post contém os dados).



Como sabemos, o algoritmo nada mais é do que uma sequência de passos a serem executados que resolverão um problema. Os exemplo mais clássicos disso são, a receita de bolo e a troca da lâmpada, lembram?

A complexidade do algoritmo está relacionada ao trabalho que ele terá na execução. Por exemplo, quanto aumenta o custo, proporcionalmente ao número de dados?

Como fazer a escolha do algoritmo de acordo com a complexidade computacional?

  • Do ponto de vista de DESEMPENHO
    • SORT é melhor
    • BOOLEAN é pior
  • Neste caso, melhor é considerado o que exige menos trabalho.

A complexidade é medida de acordo com a quantidade de dados de entrada (n). Vejamos algumas escalas.

  • Melhor: quando são necessárias poucas execuções.
  • Médio: quando há a necessidade de probabilidade estatística
  • Pior: quando são necessárias muitas execuções.


Complexidade Espacial e Temporal

A complexidade espacial de um algoritmo é o espaço de memória necessário para que ele seja executado até o final. Ou seja, S(n), em que S é o espaço de memória exigido e n o tamanho da entrada.

Já a complexidade temporal é o tempo de execução, ou seja, o tempo que um algoritmo demora para ser executado. Ele pode ser representado por T(n), sendo que T é o tempo de execução em função do tamanho da entrada, representado por n.

Notação de O grande

Na prática, é difícil (senão impossível) prever com rigor o tempo de execução de um algoritmo ou programa. 
  • Para obter o tempo é necessário pelo menos: constantes multiplicativas (normalmente estas constantes são tempos de execução de operações atômicas) e parcelas menos significativas  para  os valores grandes de n.
  • Identificam-se  as operações dominantes (mais frequentes ou mais demoradas) e determina-se o número de vezes que são executadas (e não o tempo de cada execução, que seria uma constante multiplicativa).
Maiores detalhes da análise assintótica, podem ser acessadas neste link: Ordem de O.

Classes de Complexidade

Conforme visto anteriormente, a complexidade computacional é um ramo da matemática computacional que estuda a eficiência dos algoritmos. 

Para medir esta eficiência, frequentemente utilizamos um tempo teórico que o programa leva para encontrar uma resposta em função dos dados de entrada.

Se a dependência do tempo com relação aos dados da entrada for polinomial, o programa é considerado rápido, pois dado um polinômio p(x) sabemos que |p(x)| cresce para +∞ que |x|cresce Porém, se a dependência do tempo for exponencial, o programa/algoritmo é considerado lento.

  • Complexidade constante: O(1) - Independente do número de entradas tem um número fixo de execuções.
  • Complexidade logarítmica: O(n) - A operação é realizada para cada elemento de entrada. Exemplo: Lista.
  • Complexidade linear: (n) - Ocorre em algoritmos que o problema é dividido em problemas menores. Exemplo: Árvore, Algoritmo de busca binária.
  • Complexidade nLogN: O(nLogn) - Mesmo que o anterior, (ocorre em algoritmos em que o problema é dividido em problemas menores), mas que junta as soluções dos problemas menores para compor outras soluções. Exemplo: Algoritmos de execução externa, como vetores auxiliares, MergeSort.
  • Complexidade Quadrática: O(n2) - Processado aos pares.
  • Complexidade Cúbica: O(n3) - Mesmo que o anterior (processado aos pares), mas com três laços de repetições.
  • Complexidade Exponencial: O(n2) - Este é o pior de todos. Geralmente não são úteis do ponto de vista prático porque envolve muita complexidade. Exemplo: tentar descobrir uma senha na "força bruta", ou seja, combinação de todos os caracteres.

Existem várias classes de complexidade, as mais importantes são P e NP.

A classe de algoritmos P é formada pelos procedimentos para os quais existe um polinômio p(n) que limita o número de passos do processamento se este for iniciado com uma entrada n.

A classe de algoritmos NP é aquela para as quais podemos verificar, em tempo polinomial, se uma solução possível é correta.
Os problemas de P estão contidos nos de classe NP. Se um algoritmo pode ser executado em tempo polinomial e tivermos em mãos um possível candidato S à solução, é possível executar o programa, obter uma solução correta C e comparar com com S, para certificar que S é de fato uma solução, tudo em tempo polinomial. 

Fontes utilizadas para compor este post:

http://www-usr.inf.ufsm.br/~andrezc/ia/complexidade.pdf
http://www.ime.usp.br/~pf/analise_de_algoritmos/aulas/NPcompleto2.html

O livro:

Projeto de algoritmos: Fundamentos, análise e exemplos da internet

 Por Michael T. Goodrich,Roberto Tamassia


Nenhum comentário:

Postar um comentário