22 abril 2011

Algoritmos - Programação #5

Introdução


Para resolver um problema no computador é necessário que seja primeiramente encontrada uma maneira de descrever este problema de uma forma clara e precisa. É preciso que encontremos uma seqüência de passos que permitam que o problema possa ser resolvido de maneira automática e repetitiva. Esta seqüência de passos é chamada de algoritmo. Um exemplo simples e prosaico de como um problema pode ser resolvido se fornecermos uma seqüência de passos que mostrem a solução é uma receita de bolo.
A noção de algoritmo é central para toda a computação. A criação de algoritmos para resolver os problemas é uma das maiores dificuldades dos iniciantes em programação em computadores.
No seu livro Fundamental Algorithms vol. 1 Donald Knuth apresenta uma versão para a origem desta palavra. Ela seria derivada do nome de um famoso matemático persa chamado Abu Ja´far Maomé ibn Mûsâ al-Khowârism (825) que traduzido literalmente quer dizer Pai de Ja´far, Maomé, filho de Moisés, de Khowârizm. Khowârizm é hoje a cidade de Khiva, na ex União Soviética. Este autor escreveu um livro chamado Kitab al jabr w´al-muqabala (Regras de Restauração e Redução). O título do livro deu origem também a palavra Álgebra.
O significado da palavra é muito similar ao de uma receita, procedimento, técnica, rotina. Um algoritmo é um conjunto finito de regras que fornece uma sequência de operações para resolver um problema específico.
Um algoritmo opera sobre um conjunto de entradas (no caso do bolo, farinha ovos, fermento, etc.) de modo a gerar uma saída que seja útil (ou agradável) para o usuário (o bolo pronto). Um algoritmo tem cinco características importantes:
Finitude:
Um algoritmo deve sempre terminar após um número finito de passos.
Definição:
Cada passo de um algoritmo deve ser precisamente definido. As ações devem ser definidas rigorosamente e sem ambiguidades.
Entradas:
Um algoritmo deve ter zero ou mais entradas, isto é informações que são lhe são fornecidas antes do algoritmo iniciar.
Saídas:
Um algoritmo deve ter uma ou mais saídas, isto é quantidades que tem uma relação específica com as entradas.
Efetividade:
Um algoritmo deve ser efetivo. Isto significa que todas as operações devem ser suficientemente básicas de modo que possam ser em princípio executadas com precisão em um tempo finito por um humano usando papel e lápis. 

É claro que todos nós sabemos construir algoritmos. Se isto não fosse verdade, não conseguiríamos sair de casa pela manhã, ir ao trabalho, decidir qual o melhor caminho para chegar a um lugar, voltar para casa, etc. Para que tudo isto seja feito é necessário uma série de entradas do tipo: a que hora acordar, que hora sair de casa, qual o melhor meio de transporte, etc.
Um fator importante é pode haver mais de um algoritmo para resolver um problema. Por exemplo, para ir de casa até o trabalho, posso escolher diversos meios de transportes em função do preço, conforto, rapidez, etc. A escolha será feita em função do critério que melhor se adequar as nossas necessidades.
Um exemplo de algoritmo pode ser as instruções que um professor de ginástica passa aos seus alunos em uma academia de ginástica. Por exemplo:
  1. Repetir 10 vezes os quatro passos abaixo:
    1. Levantar e abaixar braço direito;
    2. Levantar e abaixar braço esquerdo;
    3. Levantar e abaixar perna esquerda;
    4. Levantar e abaixar perna direita.

Para mostrar outro exemplo de algoritmo considere o seguinte problema. Dispomos de duas vasilhas com capacidades de 9 e 4 litros respectivamente. As vasilhas não tem nenhum tipo de marcação, de modo que não é possível ter medidas como metade ou um terço. Mostre uma seqüência de passos, que usando as vasilhas de 9 e 4 litros encha uma terceira vasilha de medida desconhecida com seis litros de água
Uma possível solução é:
  1. Encha a vasilha de 9 litros;
  2. Usando a vasilha de 9 litros, encha a vasilha de 4 litros;
  3. Despeje o que sobrou na vasilha de 9 litros (5 litros) na terceira vasilha. Observe que falta um litro para completar os seis litros;
  4. Esvazie a vasilha de 4 litros;
  5. Torne a encher a vasilha de 9 litros;
  6. Usando a vasilha de 9 litros encha a vasilha de 4 litros;
  7. Esvazie a de 4 litros;
  8. Usando o que restou na vasilha de 9 litros (5 litros), encha novamente a vasilha de quatro litros;
  9. Despeje o que sobrou na vasilha de 9 litros (1 litro) na terceira vasilha, que agora tem 6 litros.

Um outro exemplo de algoritmo é o que resolve o seguinte problema. Quatro rãs estão posicionadas em cinco casas da seguinte maneira:

rã 1rã 2rã 3rã 4

As rãs foram treinadas para trocar de casas, mas sempre obedecendo as seguintes regras:
  • elas podem pular para a casa vizinha (frente ou trás), se ela estiver vazia;
  • elas podem pular sobre a rã vizinha para uma casa livre (frente ou trás).

Mostre como as rãs podem chegar a seguinte posição final:

rã 4rã 3rã 2rã 1

Este é um problema de colocar em ordem decrescente (ordenação), tarefa muito comum em computação.
Uma possível solução para este problema é a seguinte:

rã 1rã 2rã 3rã 4
rã 2rã 1rã 3rã 4
rã 2rã 1rã 3rã 4
rã 2rã 3rã 1rã 4
rã 2rã 3rã 1rã 4
rã 2rã 3rã 4rã 1
rã 2rã 3rã 4rã 1
rã 2rã 3rã 4rã 1
rã 3rã 2rã 4rã 1
rã 3rã 2rã 4rã 1
rã 3rã 4rã 2rã 1
rã 3rã 4rã 2rã 1
rã 4rã 3rã 2rã 1

A partir de alguns exemplos anteriores podemos ver que a criação de algoritmos tem muito de inspiração. No entanto, a aparente desordem esconde alguma ordem. Observe que no problema das rãs, elas seguiram um plano básico, que era fazer com que cada uma delas, uma por vez, achasse a sua posição final. A primeira a ir para sua posição final foi a rã 1, em seguida a rã 2 e assim por diante.
----------------------------------------------

Representação de Algoritmos

As formas mais comuns de representação de algoritmos são as seguintes:
Linguagem Natural
Os algoritmos são expressos diretamente em linguagem natural, como nos exemplos anteriores.
Fluxograma Convencional
Esta é um representação gráfica que emprega formas geométricas padronizadas para indicar as diversas ações que devem ser executadas e decisões que devem ser tomadas para resolver o problema.
Pseudo-linguagem
Emprega uma linguagem intermediária entre a linguagem natural e uma linguagem de programação para descrever os algoritmos.

Não existe consenso entre os especialistas sobre qual seria a melhor maneira de representar um algoritmo. Atualmente a maneira mais comum de representar-se algoritmos é através de uma pseudo-linguagem ou pseudo-código. Esta forma de representação tem a vantagem de fazer com que o algoritmo seja escrito de uma forma que está próxima de uma linguagem de programação de computadores. Nesta apostila empregaremos preferencialmente a pseudo-linguagem.
---------------------------------------------

Linguagem Natural

Quase todos os algoritmos que apresentamos até este ponto foram escritos em linguagem natural, ou seja, no nosso caso, habitantes do Brasil, o portugês. O professor de ginástica instruiu seus alunos usando comandos em português. O quebra cabeças das vasilhas de água foi resolvido e explicado por meio de instruções dadas, novamente, em português. Somente no caso das rãs saltadoras preferimos mostrar os seus pulos por meio de uma espécie de tabela.
---------------------------------------------

Fluxogramas

Esta forma de representação de algoritmos emprega várias formas geométricas para descrever cada uma das possíveis açoes durante a execução do algoritmos. Existem algumas formas geométricas que são empregadas normalmente e que estão mostradas na Figura abaixo. Cada uma destas formas se aplica a uma determinada ação como está indicado. Existem outras formas que podem ser aplicadas, no entanto nesta apostila estas formas serão suficientes para os exemplos que serão mostrados.
Formas utilizadas em Fluxogramas

Como primeiro exemplo de um algoritmo descrito por meio de fluxogramas vamos considerar o exemplo do algoritmo para decidir o que fazer em um dia de domingo. A Figura a seguir mostra o fluxograma equivalente à descrição feita por meio da linguagem natural.

Fluxograma para decidir o que fazer em um dia de domingo.

Outro exemplo de um algoritmo descrito por meio de fluxogramas é o problema de calcular a solução da equação de primeiro grau
ax+b=0
que vale
x=-(b/a)
se a for diferente de zero. A Figura abaixo mostra um possível algoritmo para resolver este problema.

Fluxograma para equação do primeiro grau

-------------------------------------------

Pseudo Linguagem


Este modo de representar algoritmos procura empregar uma linguagem que esteja o mais próximo possível de uma linguagem de programação de computadores de alto nível mas evitando de definir regras de construção gramatical muito rígidas. A idéia é usar as vantagens do emprego da linguagem natural, mas restringindo o escopo da linguagem. Normalmente estas linguagens são versões ultra reduzidas de linguagens de alto nível do tipo Pascal ou C. No próximo capítulo veremos um exemplo de uma destas pseudo-linguagens.
---------------------------------------------

Técnicas de Construção de Algoritmos


Neste item iremos apresentar algumas técnicas empregadas na construção de algoritmos. Estas técnicas permitem construir e criar com economia de recursos algoritmos mais eficientes.
Como exemplo iremos usar uma receita que é um algoritmo descrito em lingugem natural. Para economizar texto e facilitar a apresentação a receita não mostra as quantidades dos ingredientes (as entradas). De qualquer maneira estas quantidades não são importantes para nosso estudo de algoritmos. Afinal não estamos em um curso de mestre cucas. Alguns maldosos dizem que o real motivo é que o cozinheiro não quis divulgar o seu segredo. A receita é a seguinte:
  • Filé de peixe com molho branco.
    • {preparo dos peixes}
      • Lave os filés e tempere com o suco dos limões, sal, pimenta e salsinha picada. Deixe por 1/2 hora neste tempero. Enxugue e passe cada filé na farinha de trigo. Depois passe pelos ovos batidos e frite na manteiga até ficarem dourados dos dois lados.
    • {preparo do molho branco}
      • Coloque numa panela a manteiga, a farinha e o leite e misture bem. Em fogo médio, cozinhe até engrossar. Adicione o sal, a pimenta e o queijo. Continue com a panela no fogo, cozinhando até que o queijo derreta, mexendo constantemente.
    • {juntando os dois}
      • Adicione queijo parmesão ralado e queijo gruyère. Misture e ponha sobre os filés.
  • Fim da receita do filé de peixe com molho branco.

Observe que a receita foi subdividida em partes: preparo dos peixes, preparo do molho branco e finalmente juntar as duas partes. Esta é uma técnica comum na resolução de problemas: dividir para conquistar. A idéia é dividir uma grande tarefa no maior número possível de tarefas simples. Quanto mais simples forem estas tarefas mais facilmente iremos resolvê-los e mais segurança teremos que encontramos uma solução correta.
Vamos considerar agora uma outra receita que tenha molho branco como parte, para ilustrar uma outra técnica comum da criação e descrição de algoritmos. A próxima receita é esta:
  • Alface com molho branco.
    • {preparo do molho branco}
      • Coloque numa panela a manteiga, a farinha e o leite e misture bem. Em fogo médio, cozinhe até engrossar. Adicione o sal, a pimenta e o queijo. Continue com a panela no fogo, cozinhando até que o queijo derreta, mexendo constantemente.
    • {preparo da alface}
      • Derreta a manteiga. Junte a alface cortada. Salpique o sal e deixe cozinhar por uns 5 a 10 minutos ou até a alface ficar tenra, ou o líquido da panela secar.
    • {juntando os dois}
      • Junte ao molho branco e ao suco de limão. Coloque numa travessa e enfeite em volta com pão torrado cortado em triângulos.
  • Fim da receita do alface com molho branco

Imagine que os pratos abaixo fazem parte de um livro de receitas. Observe atentamente as receitas. Perceba que os dois pratos usam molho branco e que, as duas receitas, ensinam ao leitor como preparar molho branco. Imagine que este livro de receitas tem 20 outros pratos ao molho branco. É fácil perceber que este livro terá numerosas páginas uma vez que, provavelmente, outras receitas básicas (molho de tomate, molho de mostarda, etc.) estarão repetidas em vários pontos do livro. Observe agora uma nova maneira de descrever estas duas receitas:
  • Molho branco
    • Coloque numa panela a manteiga, a farinha e o leite e misture bem. Em fogo médio, cozinhe até engrossar. Adicione o sal, a pimenta e o queijo. Continue com a panela no fogo, cozinhando até que o queijo derreta, mexendo constantemente.
  • Fim da receita do molho branco
  • Filé de peixe com molho branco
    • {preparo dos peixes}
      • Lave os filés e tempere com o suco dos limões, sal, pimenta e salsinha picada. Deixe por 1/2 hora neste tempero. Enxugue e passe cada filé na farinha de trigo. Depois passe pelos ovos batidos e frite na manteiga até ficarem dourados dos dois lados.
    • {preparo do molho branco}
      • Prepare a receita básica de molho branco.
    • {juntando os dois}
      • Adicione queijo parmesão ralado e queijo gruyère. Misture e ponha sobre os filés.
  • Fim da receita do Filé de peixe com molho branco.
  • Alface com molho branco
    • {preparo do molho branco}
      • Prepare o molho branco segundo a receita básica.
    • {preparo da alface}
      • Derreta a manteiga. Junte a alface cortada. Salpique o sal e deixe cozinhar por uns 5 a 10 minutos ou até a alface ficar tenra, ou o líquido da panela secar.
    • {juntando os dois}
      • Junte ao molho branco e ao suco de limão. Coloque numa travessa e enfeite em volta com pão torrado cortado em triângulos.
  • Fim da receita do Alface com molho branco.

Observe a economia de linhas de texto que foi possível devido a separação da receita de molho branco das demais. Se o mesmo procedimento for seguido para as demais receitas básicas, é de se esperar que o livro fique mais "fininho" do que antes.
Você pode argumentar que, no método anterior, era mais rápido seguir uma receita. Agora, ao preparar o peixe ao molho branco, por exemplo, você tem de interromper a leitura, marcar a página onde você estava, abrir na página da receita de molho branco, aprender a prepará-lo e, então, retornar à receita do peixe. Você tem razão, mas, além da economia de papel, existem outras vantagens em separar a receita do molho branco. Imagine, por exemplo, que amanhã você descubra que o molho branco fica uma delícia se levar uma pitada de alho. Basta modificar a receita de molho branco, que aparece em um único lugar no livro, e todas as receitas "ao molho branco" estarão automaticamente modificadas. No método anterior, seria preciso modificar todas as receitas que usam molho branco, com o risco considerável de esquecermos de modificar alguma delas.
Observe ainda a variação abaixo da receita do peixe:
  • Filé de peixe com molho branco
    • {preparo dos peixes}
      • Lave os filés e tempere com o suco dos limões, sal, pimenta e salsinha picada. Deixe por 1/2 hora neste tempero. Enxugue e passe cada filé na farinha de trigo. Depois passe pelos ovos batidos e frite na manteiga até ficarem dourados dos dois lados.
    • {preparo do molho branco}
      • Compre molho branco no supermercado
    • {juntando os dois}
      • Adicione queijo parmesão ralado e queijo gruyère. Misture e ponha sobre os filés.
  • Fim da receita do filé de peixe com molho branco.

Você prestou atenção? Ao invés de ensinar a preparar molho branco, a receita instrui você a comprá-lo pronto, no supermercado. Ou, em outras palavras, é possível usar no preparo do seu prato, ingredientes já prontos, preparados por outra pessoa, que você talvez nem conheça. Além disso, se você não é um cozinheiro experiente, o molho à venda no supermercado já foi suficientemente testado e é, provavelmente, gostoso. Embora, nem todos vão concordar com tal infâmia! Você já tem problemas suficientes tentando preparar um bom peixe. Talvez seja melhor usar o molho do supermercado e não ter de se preocupar com essa parte do problema. O uso de algoritmos criados por outros é muito comum na informática e pode reduzir consideravelmente o tempo de criação de um sistema.
Toda a discussão acima tem uma forte analogia com o estudo de algoritmos e técnicas de programação. Isto ficará mais claro para você mais tarde, quando estudarmos procedimentos e funções.
Para ilustrar mais um conceito importante de algoritmos vamos analisar mais um exemplo, considerando o problema de calcular a área de uma mesa retangular. Este cálculo pode ser efetuado se seguirmos os seguintes passos.
  • Cálculo da área de uma mesa.
    • Medir a largura da mesa e anotar o resultado.
    • Medir o comprimento da mesa e anotar o resultado.
    • Multiplicar o comprimento pela largura e anotar o resultado.
    • O valor da área da mesa é o resultado anotado no passo anterior.
  • Fim do cálculo da área da mesa.

Vamos supor agora que dispomos de uma mesa e de uma toalha cobrindo esta mesa e gostaríamos de saber as áreas da toalha e da mesa. O algoritmo pode ser escrito da seguinte maneira.
  • Cálculo das áreas de uma mesa e de uma toalha.
    • Cálculo da área de uma mesa.
      • Medir a largura da mesa e anotar o resultado.
      • Medir o comprimento da mesa e anotar o resultado.
      • Multiplicar o comprimento pela largura e anotar o resultado.
      • O valor da área da mesa é o resultado anotado no passo anterior.
    • Fim do cálculo da área da mesa.
    • Cálculo da área da toalha.
      • Medir a largura da toalha e anotar o resultado.
      • Medir o comprimento da mesa e anotar o resultado.
      • Multiplicar o comprimento pela largura e anotar o resultado.
      • O valor da área da toalha é o resultado anotado passo anterior.
    • Fim do cálculo da área da toalha.
  • Fim do cálculo das áreas da mesa e da toalha.

Note que os algoritmos para cálculo da área da mesa e da toalha são parecidos, trazendo a idéia que existe um algoritmo mais geral que é o de cálculo da área de um objeto retangular. Este algoritmo mais geral pode ser então aplicado tanto à mesa como à toalha. Este algoritmo mais geral poderia ser descrito da seguinte maneira:
  • Cálculo da área de um objeto retangular ou quadrado.
    • Medir a largura do objeto e anotar o resultado.
    • Medir o comprimento do objeto e anotar o resultado
    • Multiplicar o comprimento pela largura e anotar o resultado.
    • O valor da área e o resultado anotado no passo anterior.
  • Fim do cálculo da área de um objeto retangular ou quadrado.

O algoritmo para cálculo da área da mesa e da toalha poderia ser reescrito de forma mais compacta com as seguintes instruções:
  • Calcular a área da mesa usando o algoritmo acima.
  • Calcular a área da toalha usando o mesmo algoritmo.

Deste modo um mesmo algoritmo pode ser aplicado a diferentes objetos, reduzindo o número de algoritmos a serem definidos.

A maioria dos algoritmos contém decisões, por exemplo, para atravessar uma rua preciso verificar se o sinal de pedestres está verde e verificar se nenhum carro está avançando o sinal, somente após decidir se estes fatos se confirmaram poderei atravessar a rua.
Para considerar um algoritmo que inclua decisões vamos estudar um algoritmo que nos ajude a decidir o que fazer em um domingo. Um possível algoritmo poderia ser o seguinte:
  • Algoritmo de domingo.
    • Acordar.
    • Tomar o café.
    • Se estiver sol vou à praia senão leio o jornal.
    • Almoçar.
    • Ir ao cinema.
    • Fazer uma refeição.
    • Ir dormir.
  • Final do domingo.

A possibilidade de tomada de decisões é a característica mais importante de qualquer linguagem de programação. Ela permite que ao computador simular aproximadamente uma característica humana que é a escolha de opções. Sem esta característica o computador seria pouco mais do que uma veloz máquina de calcular.
Vamos agora considerar um exemplo um pouco mais matemático e estudar o algoritmo para calcular as raízes de uma equação do segundo grau da forma
ax2+bx+c=0
As raízes podem ser calculadas pelas fórmulas

x1=[-b+(b2-4ac)(1/2)]/(2a)

x2=[-b-(b2-4ac)(1/2)]/(2a)
Aparentemente o algoritmo se reduziria ao cálculo da fórmula, no entanto ao detalharmos as ações devemos prever tudo que pode acontecer durante o cálculo desta fórmula. Por exemplo o que fazer se o valor do coeficiente a for igual a zero? Um possível algoritmo é o seguinte:
  • Algoritmo para cálculo de uma equação do segundo grau.
    • Obter os coeficientes a, b e c
    • Se o coeficiente a for igual a zero informar que esta não é uma equação do segundo grau e terminar o algoritmo.
    • Caso contrário continue e faça
      • Calcular delta=b2-4ac
      • Se o valor de delta for negativo informar que a equação não tem raizes reais e terminar o algoritmo.
      • Caso contrário continue e faça
        • Calcular a raiz quadrada de delta e guardar o resultado como raiz
        • Calcular x1=(-b + raiz)/(2a)
        • Calcular x2=(-b - raiz)/(2a)
        • Fornecer como resultado x1 e x2
        • Terminar o algoritmo.
  • Fim do algoritmo para cálculo de uma equação do segundo grau.
Neste algoritmo em diversos pontos tivemos de tomar decisões e indicar o que fazer em cada uma das possibilidades, mesmo que seja mostrar que não podemos continuar o algoritmo. Toda vez que decisões tiverem de ser tomadas devemos incluir todas as possibilidades para o evento que estamos considerando.
Este é um dos possíveis algoritmos por diversas razões. Por exemplo, poderíamos incluir no algoritmo o cálculo das raízes imaginárias ou no caso do coeficiente a ser igual a zero calcular como se fosse uma equação do primeiro grau.

0 comentários:

Postar um comentário

Cadastre-se

Receba atualizações por email .

Copyright © 2011 PortalTecch.net, Todos os direitos reservados.