Autor: ' Juliana Campos *-* | Publicado: 2010-10-25T05:32:00-07:00

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. Além disto é preciso definir como os dados que serão processados serão armazenados no computador. Portanto, a solução de um problema por computador é baseada em dois pontos: a seqüência de passos e a forma como os dados serão armazenados no computador. Esta seqüência de passos é chamada de algoritmo. Um exemplo simples e prosaico, de como um problema pode ser resolvido caso forneçamos uma seqüência de passos que mostrem a solução, é uma receita para preparar um 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. Isto porque não existe um conjunto de regras, ou seja um algoritmo, que nos permita criar algoritmos. Caso isto fosse possível a função de criador de algoritmos desapareceria. Claro que existem linhas mestras e estruturas básicas, a partir das quais podemos criar algoritmos, mas a solução completa depende em grande parte do criador do algoritmo. Geralmente existem diversos algoritmos para resolver o mesmo problema, cada um segundo o ponto de vista do seu criador. 
O significado da palavra é muito similar ao de uma receita, procedimento, técnica, rotina. Um algoritmo é um conjunto finito de regras que fornece uma seqüência de operações para resolver um problema específico. Segundo o dicionário do prof. Aurélio Buarque de Holando um algoritmo é um: "Processo de cálculo, ou de resolução de um grupo de problemas semelhantes, em que se estipulam, com generalidade e sem restrições, regras formais para a obtenção de resultado ou de solução de problema." 
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 é quantidades 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 é que pode haver mais de um algoritmo para resolver um determinado problema. Por exemplo, para ir de casa até o trabalho, posso escolher diversos meios de transporte 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. 
Este é um problema de colocar em ordem um conjunto de dados, no caso ordenaçào decrescente, tarefa muito comum em computação. Uma possível solução para este problema esta mostrada na Figura a seguir. Observe que em negrito estão as rãs que estão no momento sendo dirigidas para o seu destino. 
<img alt="Movimentação das rãs até chegar na
  posição final." src="http://equipe.nce.ufrj.br/adriano/c/imagens/ras.gif" />&nbsp; Linguagem Natural Como ilustração de algoritmo em linguagem natural vamos considerar a receita abaixo. Por economia de texto e facilidade a receita não mostra as quantidades dos ingredientes (as entradas). Alguns mais maldosos dizem que o cozinheiro não quis divulgar o seu segredo. 
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. 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) FluxogramasEsta 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. 
 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.

 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=0que vale 
x=-(b/a)
se a for diferente de zero. A Figura abaixo mostra um possível algoritmo para resolver este problema. 

&nbsp; Pseudo LinguagemEste 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. Tipos de DadosOs algoritmos irão manipular dados, que normalmente são fornecidos pelos usuários, e entregar resultados para estes usuários. Uma pergunta importante neste momento é: que tipo de dados poderemos manipular? As linguagens de programação normalmente estabelecem regras precisas para definir que tipos de dados elas irão manipular. A pseudo-linguagem a-- também estabelece, ainda que informalmente, algumas regras que limitam o conjunto de dados existentes na natureza e que poderão ser manipulados pelos algoritmos. 
Existem três tipos básicos de dados que a linguagem irá manipular: 
Dados numéricos 
Dados alfa-numéricos 
Dados Logicos 
Dados NuméricosOs dados numéricos que os algoritmos podem manipular são de dois tipos: 
Dados inteiros 
Dados reais 
O conjunto dos dados inteiros pode ser definido como Z={...,-3,-2,0,1,2,...}. O conjunto dos números reais inclui o conjunto dos números inteiros, dos números fracionários e dos números irracionais. O conjunto dos números fracionários pode ser formalmente definido como Q={p/q | p,q pertencem a Z}. O conjunto dos números irracionais engloba aqueles que não podem ser representados por uma fração, por exemplo o número PI=3.141515... Os números irracionais são armazenados até um certo número de casas decimais que o computador consegue representar a partir daí as casas decimais são descartadas. 
Neste ponto é importante lembrar que dois fatos importantes. Primeiro computadores trabalham com uma base diferente de 10. Computadores trabalham em base 2 e no processo de conversão entre a base 10 e a base 2 podem ocorrer problemas de perda de dígitos significativos. Por exemplo, o número real 0.6 ao ser convertido para a base dois gera uma dízima periódica. Outro fato importante é que a memória do computador é limitada e portanto o número de dígitos binários que podem ser armazenados é função deste tamanho. Deste modo o processo de conversão e desconversão entre bases pode causar perda de informação.
Os dados inteiros tem a seguinte forma: NúmeroInteiro = [+,-]algarismo{algarismo}
O sinal de + e - entre colchetes significa que um número inteiro pode ou não ter sínal, isto é o sinal é opcional. Em seguida temos um algarismo que é obrigatório. Isto é dados inteiros tem de ter pelo menos um algarismo. A seguir temos a palavra algarismo entre chaves, o que significa que um número inteiro deve ter pelo menos um algarismo e pode ser seguido por uma seqüência de algarismos. 
São portanto exemplos de números inteiros: 
+3 
3 
-324 
Os dados reais tem a seguinte forma: [+,-]algarismo{algarismo}"."algarismo{algarismo}. Ou seja um número real pode ou não ter sinal, em seguida um conjunto de pelo menos um algarismo, um ponto decimal e depois um conjunto de pelo menos um algarismo. É importante notar que o separador entre a parte inteira e a fracionário é o ponto e não a vírgula.
São exemplos de números reais: 
0.5 
+0.5 
-3.1415 VariáveisSão os nomes que utilizamos para referenciar as posições de memória. Como já foi mostrado no capítulo de Introdução, a memória de um computador pode ser entendida como um conjunto ordenado e numerado de palavras. Na maioria dos PCs que usamos diariamente a memória pode ser considerada como um conjunto ordenado e numerado de bytes (8 bits). As linguagens de programação de alto nível atribuem nomes as posições de memória que armazenam os dados a serem processados. Deste modo os programadores tem mais facilidade para construir seus algoritmos. Na linguagem a-- um nome de variável é contruído da seguinte maneira: uma letra seguida por um conjunto de letras ou algarismos. Por exemplo, os nomes seguintes são nomes de variáveis válidos: 
i 
valor 
nome 
nota1 
Como nomes inválidos podemos dar os seguintes exemplos: 
2nota (nome começado por algarismo) 
nome de aluno (nome com espaços em branco no meio) 
Durante a apresentação da linguagem iremos fazer referências a listas de variáveis. Uma lista de variáveis é um conjunto de nomes de variáveis separados por vírgulas, por exemplo: Ex. nota1, nota2, media 
Na linguagem a-- uma variável não precisa ser definida antes de ser usada em um algoritmo. A variável irá assumir, dinamicamente, o tipo do dado que estiver sendo atribuído a esta variável. Por exemplo se armazenarmos o valor 5 em uma variável ela passará a ser do tipo inteiro. Caso resolvamos trocar o valor para 3.14 a variável passará a ser real.
Expressões lógicas são aquelas cujo resultado pode somente assumir os valores verdadeiro ou falso. Os operadores lógicos e sua ordem de precedência são mostrados na Tabela a seguir. 



Operador 

Descrição 

Prioridade 


ou 

Ou lógico 

3 


e 

E lógico 

2 


não 

Não lógico 

1 


Estes operadores e seus dados também possuem uma espécie de tabuada que mostra os resultados de operações básicas. A Tabela a seguir mostra os resultados da aplicação destes operadores à duas variáveis lógicas. 

ABA ou BA e Bnão A
falsofalsofalsofalsoverdadeiro
falsoverdadeiroverdadeirofalsoverdadeiro
verdadeirofalsoverdadeirofalsofalso
verdadeiroverdadeiroverdadeiroverdadeirofalso


Exemplos de AlgoritmosAlgoritmo de Euclides 
Dados dois números positivos m e n encontre seu maior divisor comum, isto é o maior inteiro positivo que divide tanto m como n. Assuma que m é sempre maior que n, e n diferente de zero. principal () início
ler m, n; 
r = m % n; // resto da divisão de m por n 
enquanto r != 0 faça
m = n; 
n = r; 
r = m % n;

fim do enquanto 
imprimir n;

fim de principal
Este algoritmo escrito em C pode ser visto no arquivo: au1ex1.c 

Multiplicação de dois números inteiros positivos
principal () início// achar quanto vale m*n
ler m, n; 
r = 0; 
enquanto n != 0 faça
r = r + m; 
n = n-1;

fim do enquanto 
imprimr r;

fim de principal
Este algoritmo escrito em C pode ser visto no arquivo: au1ex2.c 

Resolução de uma equação do segundo grau.
Neste algoritmo vamos assumir que o coeficiente a da equação é sempre diferente de 0. 
principal () início
ler a, b, c 
delta = b*b-4*a*c 
se delta &lt; 0
então imprimir ¨Não há raizes reais.¨

senão início
x1 = (-b + sqrt(delta))/(2*a) 
x2 = (-b + sqrt(delta))/(2*a) 
imprimir x1, x2


fim de se

fim
Este algoritmo escrito em C pode ser visto no arquivo: au1ex3.c