Análise de Algoritmos

Palavras-Chave

Fonte: Unsplash/Kevin Ku

Um algoritmo pode ser definido por:

Uma sequência bem definida de procedimentos computacionais (passos) que levam uma entrada a ser transformada em uma saída.

Cormen et al. 1991

A análise de algoritmos é a atividade de avaliar a qualidade de um algoritmo para a resolução de um problema. Nesta análise são comparados diversos algoritmos que resolvem um mesmo problema para então discernir qual o mais indicado à sua resolução.

Duas maneiras de se comparar algoritmos são através de seu desempenho (complexidade) e de sua solução (completude).

A Solução de um Algoritmo

Em um algoritmo a saída deve corresponder a uma solução válida para o problema. A solução de um algoritmo refere-se a resposta de um algoritmo para uma instância de um problema.

A análise da solução de um algoritmo consiste em saber o quão boa é a resposta de um algoritmo para uma instância de um problema, indiferente da quantidade de passos necessários para a sua obtenção.

O Desempenho de um Algoritmo

O desempenho (complexidade) de um algoritmo refere-se a quantidade de recursos computacionais utilizados para que este algoritmo obtenha a solução para um problema.

Em um computador, um processador é capaz de processar várias instruções em uma sequência. Isso significa que o processador leva um tempo para executar cada instrução. O tempo de processamento de um algoritmo deve ser finito. Assim, existe uma quantidade limitada de instruções que um processador é capaz de processar em uma quantidade arbitrada de tempo. Desta forma, quanto maior o número de instruções contidas em um algoritmo, mais tempo será necessário para a obtenção de uma solução.

Neste contexto, a análise de desempenho de um algoritmo consiste em saber a quantidade de instruções que um algoritmo precisa para retornar a solução de uma ou várias instâncias de um problema, indiferente a qualidade de sua solução.

Eficiência de um Algoritmo

A eficiência de um algoritmo é a medida quantitativa inversa da quantidade de instruções requeridas para a execução do algoritmo. Quanto maior a eficiência de um algoritmo, menos instruções são necessárias, portanto, menos recursos computacionais são gastos.

Os dois principais métodos de mensuração da eficiência de um algoritmo são:

  1. O método experimental;
  2. O método analítico.

O Método Experimental

O método experimental consiste em:

  1. implementar diversos algoritmos;
  2. executar os algoritmos um grande número de vezes;
  3. analisar os resultados.

No método experimental, o tempo de execução não depende somente do algoritmo, mas do conjunto de instruções do processador, a qualidade do compilador, a habilidade do programador etc. Neste método, o tempo de processamento pode ser mensurado através do próprio sistema operacional ou por meio de um algoritmo de testes.

O algoritmo de testes avalia a complexidade do algoritmo para várias instâncias de um problema, cada qual com diferentes ordens de grandeza $(n)$. A dificuldade em se utilizar algoritmos de testes é a limitação no número de testes que podem ser realizados por eles, ou seja, caso exista alguma instância de ordem $n$ não testada, não será possível saber o comportamento do algoritmo simplesmente por esta instância não ter sido testada.

O Método Analítico

O objetivo do método analítico é encontrar funções matemáticas que descrevem o crescimento do tempo de processamento dos algoritmos em relação ao tamanho da entrada e comparar estas funções (Figura 1).

Figura 1 – Análise quantitativa do desempenho de um algoritmo.Fonte: Autor.

onde:

  • $n$ é o ordem da instância do problema;
  • $T(n)$ é a função matemática que descreve o crescimento do tempo de execução do algoritmo.

Estas curvas podem ser obtidas por meio da modelagem matemática do problema deduzida a partir do próprio algoritmo ou a partir de dados estimados de forma empírica, ou seja, implementando o programa, coletando os resultados e seguir montando estas curvas estatisticamente com estes resultados.

As curvas apresentam características diferentes para cada algoritmo utilizado para a solução de um mesmo problema. Por meio do gráfico podemos observar que para um problema do mesmo tamanho e com as mesmas características, um algoritmo pode apresentar soluções bastante diversas.

A observação de tamanhos de entradas grande o suficiente, de forma que apenas a ordem de crescimento do tempo de processamento seja relevante é conhecida como a análise assintótica da eficiência de um algoritmo.

A análise assintótica pode ser o fator determinante do sucesso de um software. O google é um exemplo de alta eficiência dos algoritmos de buscas utilizados pela empresa, superiores aos demais concorrente e um dos responsáveis pelo seu sucesso no mercado.

Aplicação da Análise de um Algoritmo

A análise de um algoritmo é realizada através da aplicação das técnicas de análise do desempenho e da solução de um algoritmo.

Para algoritmos mais simples é possível utilizar de análise matemática através de deduções de fórmulas ou provas matemáticas (método analítico). O método analítico é o mais complexo porque dele é possível obter garantias de que o algoritmo sempre obterá soluções de qualidade com um desempenho determinístico.

Em algoritmos mais complexos muitas vezes não se existe uma definição completa para o problema tratado. Como, por exemplo, o sistema de usuários de um e-commence para compras online (amazon, mercado livre, submarino etc), que não utilizam de uma definição formal para obtenção da solução de seus problemas. Para tal, o que existe é uma série de estudos em engenharia de software para o levantamento de requisitos que vai tentar construir estas definições, o que torna sua abordagem mais complexa. Da mesma forma existem aplicações, tais como os jogos de computador, tão complicadas e dotadas de tantos aspectos diferentes que se torna difícil utilizar da análise matemática para obter garantias de quão bom um algoritmo é quando comparado a outro. Nessa conjuntura, para algoritmos mais complexos é utilizada uma estratégia de análise empírica (ou subjetiva). A análise empírica ou empirismo adota o método experimental para a observação, ou seja, adota uma análise estatística para obter a soluções de um problema com um desempenho estimado. Na análise empírica, as estatísticas são retiradas das execuções do método experimental. Das estatísticas obtidas é estimada a expressão que reflete o comportamento do algoritmo (Gamers Benchmarking). Na maioria das vezes, a escolha de um algoritmo é feita através de critérios empíricos como:

  1. facilidade de compreensão, codificação e depuração;
  2. eficiência na utilização dos recursos do computador e rapidez.

Logo, um problema pode ser resolvido através de diversos algoritmos (análise de completude). Contudo, o fato de um algoritmo resolver um dado problema não significa que a sua solução seja aceitável na prática (análise da complexidade). Assim, a análise de um algoritmo fornece uma medida objetiva da solução de um problema de forma proporcional ao tempo de processamento do algoritmo.

Ordem $(n)$ Método de Cramer $T_C(n)$ Método de Gauss $T_G(n)$
2 22us 50us
3 102us 159us
4 456us 353us
5 2,35ms 666us
10 1,19min 4,95ms
20 15255 séculos 38,65ms

Neste contexto, analisar um algoritmo significa prever os recursos de que o algoritmo necessitará para obtenção da solução de um problema e estimar o seu tempo de processamento. Em outras palavras, encontrar a eficiência de um algoritmo pela observação da quantidade de recursos que ele consome através de alguns critérios, tais quais:

  • operações de entrada e saída;
  • operações aritméticas;
  • operações lógicas e relacionais;
  • movimentação de dados entre os componentes;
  • atribuições, declarações de métodos e variáveis;
  • estrutura de decisão e repetição;
  • chamadas de métodos etc.

aplicando os seguintes procedimentos:

  1. definir a ordem $(n)$ do problema;
  2. contabilizar o custo de cada linha, assumindo que cada operação tem 1 custo (ou unidade de tempo);
  3. contabilizar quantas vezes (no máximo) cada linha é executada;
  4. somar o custo total de cada linha.

Para a análise de um algoritmo é necessário a análise de todas as suas condições possíveis.

Tipicamente, são avaliadas três condições para descrever um algoritmo:

  • melhor caso (custo mínimo);
  • pior caso (custo máximo);
  • caso médio (custo médio).

Diferentes algoritmos variam em cada um destes aspectos. Como, por exemplo, alguns algoritmos de ordenação possuem a mesma complexidade de “caso médio”, porém tem um “pior caso” pior que o outro. Existem situações em que isso não é um problema e outras em que o “pior caso” de um algoritmo é muito ruim. Com estas informações podemos discutir a qualidade dos algoritmos em uma determinada situação (Figura 2).

Figura 2 – Análise do algoritmo de busca binária.Fonte: Autor.

Referências

  • PIVA JÚNIOR, Dilermando (et al). Estrutura de dados e técnicas de programação. 1. ed. Rio de Janeiro, RJ: Campus, 2014. 399 p. ISBN: 9788535274370.
  • CORMEN, Thomas H et al. Algoritmos: teoria e prática. Rio de Janeiro: Elsevier, 926 p. ISBN: 9788535236996.
  • TOSCANI, Laira Vieira; VELOSO, Paulo A. S. Complexidade de algoritmos: análise, projeto e métodos. 3. ed. Porto Alegre: Bookman, 2012. 261 p. (Série livros didáticos informática UFRGS, 13) ISBN: 9788540701380.
  • ASCENCIO, Ana Fernanda Gomes. Estruturas de dados: algoritmos, análise da complexidade e implementações em Java e C/C++. São Paulo: Pearson, c2010. 432 p. ISBN: 9788576052216, 978857605816.
  • BRASSARD, Gilles; BRATLEY, Paul. Fundamentals of algorithmics. Englewood Cliffs: Prentice Hall, c1996. xx, 524 p. ISBN: 0133350681.

Livraria