Escolar Documentos
Profissional Documentos
Cultura Documentos
INTRODUÇÃO
No decorrer da aprendizagem de lógica e programação, vimos que os computadores operam seguindo uma lista de instruções estabelecida para
eles e, ainda, que os computadores gastam muito tempo ordenando e pesquisando as coisas, percebemos isso quando praticamos a organização
dos dados (estruturação). Portanto, devemos descobrir métodos rápidos e eficientes para fazer isto. Imagine você tendo que implementar uma
estrutura para manter o cadastro de mais de 5 mil funcionários? Onde manter significasse: assegurar em cada ficha a manutenção e atualização de
30 campos de cada ficha, além de garantir a listagem ordenada de cada ficha.
Ou seja, os algoritmos fazem parte do dia a dia das pessoas, pois, é uma sequência de ações executáveis para chegar à solução de um determina -
do tipo de problema. Segundo Edsger Dijkstra, um algoritmo corresponde a uma descrição de um padrão de comportamento, expresso em ter-
mos de um conjunto finito de ações.
Desta forma, a análise de algoritmos (descrita e difundida por D.E. Knuth) tem como função determinar os recursos necessários para executar um
dado algoritmo. Ela estuda a correção e o desempenho através da análise de correção e da análise de complexidade. Dados dois algoritmos
para um mesmo problema, a análise permite decidir qual dos dois é mais eficiente.
Antes de partir para conhecer as diferenças entre os tipos e análises de algoritimos, saibamos que para determinar se um algoritmo é o mais efici -
ente, podemos utilizar duas abordagens:
Análise Empírica
Envolve avaliar o custo (ou a complexidade) de um algoritmo a partir da avaliação da execução do mesmo quando implementado. Ou seja, um
algoritmo é analisado pela execução de seu programa correspondente.
2
Algumas vantagens podemos adquirir quando realizamos a análise empírica, como por exemplo:
Podemos nos deparar com algumas desvantagens ou dificuldades quando realizamos a análise empírica, como por exemplo:
1. Ignora-se o detalhamento sobre: linguagem de programação utilizada, o hardware no qual o algoritmo é executado, conjunto de instruções da
cpu.
2. Permite a compreensão de como o algoritmo se comporta à medida que o conjunto de dados de entrada cresce (podemos então expressar a
relação entre o conjunto de dados de entrada e a quantidade de tempo necessária para processar esses dados).
Podemos começar a Análise Matemática de um algoritmo apenas “contando” as suas instruções simples até se chegar um axioma (proposições
aceitas como verdadeiras sem demonstração e que servem de base para o desenvolvimento de uma teoria), para podermos então encontrar o
melhor, caso médio e pior caso de determinado algoritimo.
Vamos considerar que as instruções simples de um algoritmo serão as que provavelmente são as executadas pelo cpu ou algo muito perto disso.
Vejamos alguns exemplos:
Tipos de instruções:
EXEMPLO EXERCÍCIO
Enunciado: O seguinte trecho de código abaixo, demonstra partes de um algorítimo que foi construído pensando-se na realização de uma
pesquisa realizada em uma estrutura de dados composta homogênea.
int x=vet[0];
for (i=0;i<n;i++){
if (vet[i]>=x){
x=vet[i];
}
}
A. Identifique de forma coesa e sucinta o problema a qual muito provavelmente o trecho irá resolver (2 linhas).
B. Comente cada linha de instrução (relacione comandos de instrução, comparações, identifique operações aritméticas, trocas e ):
C. Identifique de forma coesa e sucinta as propriedades do problema a qual o trecho de código provavelmente irá resolver:
i. Parâmetros de Entrada:
ii. Parâmetros de Saída
iii. Propriedades:
iv. Instâncias (se houver):
D. Realize :
I. A contagem das instruções em cada linha:
II. Gere gráfico para demonstração referenciando função de tempo (considere Comparações x Instâncias)
III. Identifique : Pior, Melhor e Médio Caso do trecho de código.
Solução :
4
A. Identifique de forma coesa e sucinta o problema a qual muito provavelmente o trecho irá resolver: Irá resolver um problema de busca de uma
chave dentro de um Array cujo tamanho é definido pela constante n. (particularmente, algoritmo que busca o maior valor presente em um vetor “vet”, contendo “n”
elementos e o armazena na variável “x”)
B. Comente cada linha de instrução (relacione comandos de instrução, comparações, identifique operações aritméticas, trocas e ):
C. Identifique de forma coesa e sucinta as propriedades do problema a qual o trecho de código provavelmente irá resolver:
D. Faça :
I. A contagem das instruções em cada linha:
II. Gere a função / axioma matemático que você pode encontrar da contagem das funções
III. Teste com instâncias inseridas (à seu critério)
IV. Gere gráfico para demonstração referenciando função de tempo (considere Comparações x Instâncias)
V. Identifique : Pior, Melhor e Médio Caso do trecho de código.
Assumindo que as instruções possuem um mesmo “custo” e os “comandos de seleção” possuem um custo zero (ou seja, a linha contendo o
comando que vai inicializar a estrutura da repetição não custa nada, o que custa é a comparação dentro da estrutura de decisão), vamos contar as
instruções no seguinte trecho de código (algoritmo que busca o maior valor presente em um vetor “vet”, contendo “n” elementos e o armazena na variável “x” ):
Resposta :
int x=vet[0]; → 1
for (i=0;i<n;i++){ → 1+1n e de novo → 1+1n
if (vet[i]>=x){
x=vet[i];
}
}
Considerando que:
1. Linha 1:
O Custo da linha 1 é de 1 (uma) instrução referente à ocorrência de uma atribuição (o que ocorre é que o valor da primeira posição do
vetor está sendo copiado para a variável “x”) referente à: acessar o valor de vet[0] e atribuí-lo à x;
2. Linha 2:
Para calcular o custo da linha 2, devemos considerar as regras para prova de corretude do algorítimo (ANTES, DURANTE e APÓS
EXECUÇÃO), desmembremos o laço/estrutura de repetição em:
Logo, teremos até aqui: 2 (duas) instruções (1+1n), sendo que uma delas é em relação à n.
Logo, até aqui, teremos: 2 (duas) instruções (1+1n), sendo que uma delas é em relação à n.
5175
6
ou
5133
1+1+1n+1+1n
Supondo até aqui, sem levar em conta a estrutura de repetição dentro do laço, se considerarmos a execução do laço vazio, já conseguimos chegar
a definir uma função matemática para expressar o custo do algoritmo em relação ao tamanho de entrada no vetor:
F(n)= 2n+3 – Axioma Matemático gerado até a linha de instrução que trata a estrutura de repetição
Logo, exemplificando, para um vetor de entrada 10, temos: F(10)=2x10+3=23 instruções. Para um vetor de entrada 20, F(20)=2x20+3=43
instruções.
Percebemos até aqui que de acordo com o axioma gerado, em relação ao custo do tempo de execução do algorítimo, ainda que ocorram instâncias
diferenciadas, não ocorrendo o aumento de tamanho da estrutura, o nº de comparações será sempre o mesmo, pois não há aumento da tamanho
da estrutura criada, porém, quando aumento do tamanho da estrutura, e consequentemente aumento do nº de entradas, percebemos que ocorrerá
aumento em relação ao consumo de tempo.
Até agora, sem e tratando da estrutura de decisão, teríamos então : 2 (duas) instruções.
- Antes de analisarmos a decisão, havíamos visto que as instruções eram sempre executadas na análise do laço/estrutura de repetição;
7
- Agora, percebemos que dentro do for, as instruções poderão ou não serem executadas, devido à decisão (vai depender dos valores que temos
dentro do vetor).
Ou seja, antes, bastava saber o tamanho do vetor, n, para definirmos a função de custo do algoritmo (Fn)).
Mas agora, precisaremos considerar também o conteúdo do vetor. Vejamos melhor no exemplo abaixo:
VetA={1,2,3,4}
VetB={4,3,2,1}
No caso de VetA, nos deparamos com a decisão (o if) sendo sempre verdadeira, nesse caso teremos supostamente mais instruções, sempre
terá a atribuição.
No caso de VetB, nos deparamos com a decisão (o if) sendo sempre falsa (a linha de atribuição nunca será executada, nunca será feito a
atribuição).
Em análise de algoritmos é comum procurarmos considerar qual seria o pior caso (em relação aos custos) de um algoritmo. No caso, o “pior
caso” seria o maior número de instruções executadas.
Neste caso do algoritmo que busca o maior valor de um vetor, o pior caso acontece quando o vetor possui valores em ordem crescente. Por quê?
Enfim, após observações, neste caso, do “pior caso”, a função de complexidade de custo em relação ao tamanho de entradas no vetor vet
sofreria alteração, passando para:
Esta também pode ser a função de complexidade de custo de tempo pois, nos dá também uma ideia de custo de execução do algoritmo para um
problema de tamanho “n”.
Encaixando-se na terminologia BIG – O, as constantes podem ser excluídas, e teremos então que:
F(n) = n