Estou escrevendo este artigo pois senti em alguns fóruns que um pessoal gosta bastante de falar sobre Spring, Struts, Hibernate, JSP, JSF, etc., mas acabam esquecendo (ou não aprendendo) alguns conceitos mais fundamentais. Também vi que muitas dúvidas são relacionadas a algoritmos, estruturas de dados, etc., principalmente em relação ao pessoal que está começando agora nesse divertido mundo do desenvolvimento de software.

Estou falando deles: Os Algoritmos! Sim, temidos por uns, adorados por outros e ignorados por mais outros. O estudo sobre Algoritmos aparece normalmente no início dos cursos relacionados à Computação e depois acabam sendo deixados mais de lado, tanto pelo curso, como pelo estudante. Ok Alexandre, então qual será o foco desta série? Vamos lá!

Algoritmos

Revisarmos sobre alguns conceitos teóricos e colocar a mão na massa em diversos problemas clássicos que aparecem nos cursos relacionados à computação e resolver outros problemas nem tão clássicos, que aparecem em cursos ligados à Matemática, como alguns problemas matemáticos clássicos dos cursos do IME-USP por exemplo.

Neste primeiro artigo vamos relembrar alguns conceitos e enfatizar os motivos do estudo sobre Algoritmos, bem como a importância de saber lidar com problemas clássicos e criar uma base um pouco mais sólida para a resolução de problemas mais complexos no seu ambiente de produção.

Como de costume, farei uma introdução bem básica a ponto de revoltar alguns que já sabem, mas com o intuito de realmente nivelar o conhecimento sobre o assunto e conseguir ajudar o pessoal que realmente está começando. Após alguns artigos, tenho certeza que colocarei algum exemplo que fará até o mais experiente pensar mais que 30 segundos! :)

Para os mais apressados, vou adiantar quais os assuntos que pretendo discutir (tentar!):

  • Conceito e definição de Algoritmos
  • Resolução de problemas com inteiros, com condições, com repetições, com vetores e matrizes
  • Funções
  • Pilhas
  • Filas
  • Análise de Algoritmos
  • Classificação de tabelas
  • Busca de registros

Ambiente utilizado

Na verdade a ideia é falar sobre Algoritmos e não sobre linguagens. Logo, você pode ler normalmente os artigos e aplicar os exemplos em Java, C, Pascal (normalmente estas 3 são utilizadas de forma acadêmica) mas sinta-se à vontade para utilizar a que você estiver acostumado.

Os Algoritmos (logo vamos resumir mais decentemente) são basicamente sequências de passos, ou seja, definiremos tais passos para a resolução de um problema específico e só no último momento (eu diria até o menos importante) passaremos para a linguagem.

Qual utilizarei nos exemplos? Utilizarei Java e C. São as mais comuns neste tipo de estudo e o pessoal gosta!

Algoritmo para quê?

Apesar de ser realmente importante o estudo de Frameworks em geral, de linguagens e etc., o estudo de algoritmos é vital para o desenvolvedor que pretende revolver problemas de programação no seu dia a dia.

Sem uma base razoável na resolução de Algoritmos, dificilmente um desenvolvedor conseguirá resolver problemas e se conseguir, é quase certeza que levará mais tempo que o normal.

É praticamente impossível um desenvolvedor ao longo do seu dia não precisar criar um algoritmo para a resolução de algum problema! Respiramos algoritmos ao longo do dia inteiro!

Definição

Um Algoritmo é uma sequência de passos para chegar em determinado lugar. Pronto! Temos aquela definição clássica do Algoritmo sendo uma receita de bolo, que nada mais é do que uma sequência de passos para chegar ao bolo pronto.

Na computação, usamos os Algoritmos para resolver determinados problemas. Em certas situações precisamos também resolver este mesmo problema, mas com uma velocidade de processamento maior (discutiremos este ponto mais para a frente), ou seja, temos agora um outro algoritmo para resolver o mesmo problema, mas de forma diferente.

Primeiro problema

Vamos começar já analisando um primeiro problema e a partir dele já vamos deixar mais clara a ideia dos "passos para chegar em determinado lugar". Como um algoritmo nasce? Ele nasce a partir de um determinado problema. Então vamos criar um problema!

Problema: Fazer a divisão de um número por outro. Se o resultado for positivo, imprimir o número encontrado pela divisão, caso seja negativo, imprimir zero. Caso o divisor seja zero, imprimir o valor -1.

Para os que estão começando agora o texto pode parecer meio estranho mas é bem simples. Vamos começar a pensar sobre este problema em passos!

  • Possível primeiro passo:Pegar os dois números
  • Possível segundo passo:Verificar o valor do divisor, que no nosso caso é o B
  • Possível terceiro passo:Se o divisor for zero, imprimimos -1, caso contrário continuamos felizes
  • Possível quarto passo: Verificar se o número encontrado após a divisão é positivo ou negativo
  • Possível quinto passo:Imprimir o número encontrado ou imprimir o valor zero.

Alexandre, por que "possível"? Simples: podemos ter outros passos além destes. Temos os famosos Baby Steps, onde podemos dar passos menores ainda que estes. Um algoritmo, apesar de ter passos bem definidos pode ter passos diferentes para o mesmo problema. Veremos alguns desses passos em um momento futuro.

Para ficar um pouco mais clara a sequência destes passos, vamos colocá-la em um fluxograma bem simples:

fluxograma

Não vamos detalhar o que é um fluxograma pois o desenho é bem simples. Ele detalha exatamente os passos que citamos.

Simples não? Basicamente pegamos um problema, dividimos o problema em possíveis passos e escrevemos um fluxograma bem simples para visualizarmos melhor o que queremos.

Resolvendo o problema em um pseudocódigo

Uma forma muito comum de se resolver problemas deste tipo, é resolvê-lo em um pseudocódigo, ou seja, um código "falso", onde não escrevemos em uma linguagem específica e sim em uma linguagem mais próxima da nossa realidade, onde qualquer pessoa possa entender.

Esta forma é válida não somente para quem está começando a desenvolver algoritmos mas também para algoritmos mais complexos. Alguns gostam de chamar esta forma de "Descrição Narrativa" dos passos a serem dados. A ideia é que qualquer pessoa realmente entenda o que está acontecendo.

Vamos lá:

Variáveis
A, B: Inteiros;
Inicio
   Escreva("Digite o primeiro número:");
   Lê o número e coloca na variável A;
   Escreva("Digite o segundo número:");
   Lê o número e coloca na variável B;
      Se (B = 0) Então
         Imprime -1;
      Se (A/B < 0) Então
         Imprime 0;
      Se (A/B > 0) Então
         Imprime A/B;
Fim

Simples não? Vamos para um próximo problema!

Segundo problema

Segundo problema: O usuário digitará um número e vamos imprimir o quadrado deste número. Caso o usuário digite o número zero finalizamos o programa.

Desta vez já vamos pular para o pseudocódigo. Vamos lá:

Variáveis
N: Inteiro;
Inicio
   Escreva("Digite o número desejado:");
   Lê o número e coloca na variável N;
   Enquanto (N diferente de 0)
   Inicio
      Imprime N*N;
      Escreva("Digite o número desejado:");
      Lê o número e coloca na variável N;
   Fim
Fim

Também bem simples. O sistema pede para o usuário digitar um número e verifica se esse número é zero. Se for diferente de zero, imprime o quadrado do número e caso seja zero, finaliza o programa.

Esta é uma forma simples e organizada de escrever os passos para a resolução de um problema. Note que realmente não precisamos de uma linguagem para resolver o problema. Não importa com o que resolveremos e sim como! É como pedir uma xícara de café: No Brasil e na China pedir um café é a mesma coisa, só mudamos a língua.

Que tal você resolver desta mesma forma um outro problema?

Terceiro problema

O sistema pede para o usuário digitar um número. Se o número for par, o sistema imprime o quadrado deste número e caso contrário imprime o cubo do número digitado. Este problema nós vamos resolver no próximo artigo, já utilizando Java e C.

Para você que está iniciando os estudos e não conhece muito bem a sintaxe das linguagens não se preocupe pois a ideia desta série é mostrar os passos para a resolução de um problema e vamos usar essas linguagens só para os problemas não ficarem tão vagos! Vamos lá!

Quebrando em pequenos pedaços

Conforme havia dito no artigo anterior, podemos dividir um problema em passos para chegar na sua resolução final. A ideia de divisão de um problema em problemas menores já é antiga e facilita muito a nossa vida, pois podemos pensar na resolução de "mini problemas", deixando de lado a visão macro do problema. Após a resolução dos pequenos problemas, o problema maior é resolvido através da união destes.

Primeira resolução

Para o nosso primeiro código, vamos atacar o problema 1 do artigo anterior. Vamos lembrá-lo:

"Problema: Fazer a divisão de um número por outro. Se o resultado for positivo, imprimir o número encontrado pela divisão, caso seja negativo, imprimir zero. Caso o divisor seja zero, imprimir o valor -1."

No artigo anterior também vimos a resolução deste problema através de um fluxograma e criamos um pseudocódigo com a intenção de fazer qualquer pessoa entender o objetivo que gostaríamos de atingir, que é a resolução do problema acima.

Ambiente

Com o problema em mãos, vamos fazer o passo a passo da resolução já utilizando as duas linguagens citadas, para que possamos visualizar o fluxo em um nível mais baixo.

Para o Java, utilizarei o Eclipse e para o C utilizarei o DevC++. Particularmente não gosto do DevC++ e uso o GCC do Ubuntu, mas o DevC++ é bem utilizado pelos que estão começando. O Eclipse talvez não seja o mais usado pelos iniciantes (o comum é usarem editores simples) , mas ele é muito conhecido. Fique à vontade para desenvolver no NetBeans, JCreator, JBuilder, etc.

Relembrando

Esqueça a sintaxe do código abaixo caso você não a entenda agora. O ponto forte aqui para você que está começando é entender o conceito, a lógica, a ideia. Pense na situação simples: Para você pedir um cafezinho, você segue alguns passos, como encontrar um local, chamar o garçom, escolher o café, ver o preço e pedir. E você vai fazer exatamente a mesma coisa se estiver no Brasil, Japão ou na África e só vai mudar o idioma, a "sintaxe"!

Portanto, entender os passos neste momento é muito mais útil e fundamental que entender a sintaxe, a linguagem.

Primeiro código em Java

Vamos criar o nosso primeiro código em Java. Para isso, vamos criar uma classe com o nome de "DivisaoDeNumeros". Esta é a classe que irá conter a nossa lógica para a resolução do problema. Com a classe criada, vamos criar o método main” para podermos executar a aplicação, ou seja, imprimir os dados.


<span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">
  //Classe que trata das divisões de números</span>
<span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">
  public class</span> DivisaoDeNumeros {
<span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">
  public static void</span> main(String[] args) {
 
    }}

Agora com a classe e o método principal criados, vamos fazer o passo a passo do artigo anterior, porém escrevendo em código! Para não ficar uma leitura muita cansativa e demorada fazendo cada passo, escrevi o código inteiro e comentei cada passo no próprio código.

<span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">public class</span> DivisaoDeNumeros {
 
    <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">public static void</span> main(String[] args) {
        <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Criamos um objeto Scanner para capturar o que foi digitado</span>
        Scanner input = <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">new</span>Scanner(System.in);
        <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Imprime mensagem para a inserção do primeiro valor</span>
        System.<span _mce_style="color: #000000;" style="color: rgb(0, 0, 0); ">out</span>.println(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"Insira o valor do dividendo: "</span>);
        <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Guarda o valor digitado pelo usuário na variável dividendo</span>
        <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">int </span>dividendo = input.nextInt();
        <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Imprime mensagem para a inserção do segundo valor</span>
        System.out.println(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"Insira o valor do divisor: "</span>);
        <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Guarda o valor digitado pelo usuário na variável divisor</span>
        <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">int </span>divisor = input.nextInt();
 
        <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Verifica se o valor do divisor é igual a zero</span>
        <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">if </span>(divisor == 0) {
            <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Imprime o valor -1 caso o divisor seja zero</span>
            System.out.println(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"-1"</span>);
        }
        <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Verifica se o valor do cálculo da divisão é negativo</span>
        <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">else if</span> ((dividendo / divisor < 0)) {
            <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Imprime o valor 0 caso o resultado da divisão seja negativo</span>
            System.out.println(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"Valor encontrado: 0"</span>);
        }
        <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">else</span> {
            <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Como o divisor não é zero e o cálculo não é negativo, imprime o resultado da divisão</span>
            System.out.println(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"Valor calculado: "</span> + dividendo / divisor);
        }
    }}

Você pode perceber que a execução está bem simples! Pelos comentários, podemos ver que passamos pelo "passo a passo" do artigo anterior, mas desta vez não escrevemos um pseudocódigo e sim um código em Java que podemos executar. Se você não está acostumado com a sintaxe, perceba que não foi difícil de entender o conceito, a ideia por de trás do código.

Esta é uma possível solução do problema, e não única. Podemos ter outros passos para a resolução! Mas será que se só trocarmos as condições (if's / else if's) teremos o mesmo resultado? Que tal tentar dar uma olhada no código abaixo e ver qual o problema?

<span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">import </span>java.util.Scanner;
 
<span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">public class</span> DivisaoDeNumeros {
 
    <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">public static void</span> main(String[] args) {
        <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Criamos um objeto Scanner para capturar o que foi digitado</span>
        Scanner input = <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">new</span> Scanner(System.in);
        <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Imprime mensagem para a inserção do primeiro valor</span>
        System.out.println(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"Insira o valor do dividendo: "</span>);
        <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Guarda o valor digitado pelo usuário na variável dividendo</span>
        <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">int </span>dividendo = input.nextInt();
        <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Imprime mensagem para a inserção do segundo valor</span>
        System.out.println(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"Insira o valor do divisor: "</span>);
        <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Guarda o valor digitado pelo usuário na variável divisor</span>
        <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">int </span>divisor = input.nextInt();
 
        <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Verifica se o valor do cálculo da divisão é negativo</span>
        <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">if</span> ((dividendo / divisor < 0)) {
                       <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); "> //imprime o valor 0 caso o resultdo da divisão seja negativo </span>
                        System.out.println(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"Valor encontrado: 0"</span>);
                }
               <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); "> //verifica se o cálculo é positivo</span>
                <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">else if</span> (dividendo / divisor > 0) {
            <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Imprime o resultado do cálculo caso o resultado seja positivo</span>
            System.out.println(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"Valor calculado: "</span> + dividendo / divisor);
        }
        <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Como o resultado não é positivo e nem negativo, podemos supor que o divisor é zero</span>
        <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">else </span>{
            <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Imprime o valor -1 pois o divisor é zero</span>
            System.out.println(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"-1"</span>);
        }
    }}

Erro! Veja como não precisamos entender a linguagem/sintaxe para saber que este código terá problemas. Se olharmos com mais "carinho" vamos perceber que o código, na primeira condição, já tenta calcular a expressão. Se você inserir o valor zero para o divisor, teremos um erro no caso do Java que é o "java.lang.ArithmeticException: / by zero", ou seja, não existe divisão por zero matematicamente falando e claro que na execução o Java vai reclamar.

Perceba que na resolução não basta simplesmente trocarmos as condições. Os passos para a resolução de um problema devem ser bem definidos e bem pensados para que nenhuma regra seja violada.

Código em C

Abaixo temos o código em C, que é muito usado nos cursos de introdução à computação:

<span _mce_style="color: #999999;" style="color: rgb(153, 153, 153); ">#include<stdio.h>
#include<stdlib.h></span>
 
<span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">int </span>main() {
   <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Declaração das variáveis para guardar os valores</span>
   <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">int </span>dividendo;
   <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">int </span>divisor;
 
   <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Imprime mensagem para a inserção do primeiro valor</span>
   printf(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"Digite o valor do dividendo:"</span>);
   <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Guarda o valor digitado pelo usuário na variável dividendo</span>
   scanf(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"%d"</span>, <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">&</span>dividendo);
 
   <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Imprime mensagem para a inserção do segundo valor</span>
   printf(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"\nDigite o valor do divisor:"</span>);
   <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Guarda o valor digitado pelo usuário na variável divisor</span>
   scanf(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"%d"</span>, <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">&</span>divisor);  
 
  <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); "> //verifica se o valor do divisor é igual a zero</span>
   <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">if </span>(divisor == 0) {
      <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Imprime o valor -1 caso o divisor seja zero</span>
      printf(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"-1\n"</span>);
   }
   <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Verifica se o valor do cálculo da divisão é negativo</span>
   <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">else if</span> ((dividendo / divisor < 0)) {
      <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Imprime o valor 0 caso o resultdo da divisão seja negativo</span>
      printf(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"Valor encontrado: 0\n"</span>);
   }
   <span _mce_style="color: #800000;" style="color: rgb(128, 0, 0); ">else </span>{
      <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Como o divisor não é zero e o cálculo não é negativo, imprime o resultado da divisão</span>
      printf(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"Valor calculado: %d \n"</span>, (dividendo / divisor));
   }
   <span _mce_style="color: #008000;" style="color: rgb(0, 128, 0); ">//Pausa a execução</span>
   system(<span _mce_style="color: #3366ff;" style="color: rgb(51, 102, 255); ">"PAUSE"</span>);}

Entendimento do conceito x Sintaxe da linguagem

Volto a lembrar que não foi preciso entender 100% a sintaxe para entender o que está acontecendo. Nos comentários do código vimos o "passo a passo" para a resolução dos algoritmos e basicamente traduzimos logo em seguida para a sintaxe utilizada no Java e no C.

Devemos lembrar também que não existe somente um passo para a resolução do problema e você pode ficar à vontade para modificar os códigos acima, criando outros passos!

Finalizando

Neste artigo vimos a resolução de um problema usando Java e C e a ideia principal é entender o conceito! Entendido o problema e os passos para a resolução dele, traduzi-lo para a linguagem é o "mais fácil". Podemos entender muito de uma linguagem, mas se não conseguirmos resolver um problema com passos bem definidos, não conseguimos fazer nada.