Algoritmos

Algoritmos, Parte II – Primeiros códigos

Fala pessoal!

Idéia
Neste artigo continuaremos a série sobre Algoritmos! No primeiro artigo resolvemos 3 problemas bem simples, utilizando a idéia de pseudocódigo, onde podemos visualizar melhor os passos para a resolução de um problema e não precisamos conhecer nenhuma linguagem de programação nesta etapa.
Neste segundo artigo vamos resolver o primeiro problema apresentado anteriormente, já utilizando Java e C.

Pra você que está iniciando os estudos e não conhece muito bem a sintaxe das linguagens não se preocupe pois a idéia 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 idéia 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 também 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, pra 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 pra você que está começando é entender o conceito, a lógica, a idéia. Pense na situação simples: Pra 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.

//Classe que trata das divisões de números
public class DivisaoDeNumeros {
    public static void 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! Pra 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.

public class DivisaoDeNumeros {

	public static void main(String[] args) {
		//Criamos um objeto Scanner para capturar o que foi digitado
		Scanner input = new Scanner(System.in);
		//Imprime mensagem para a inserção do primeiro valor
		System.out.println("Insira o valor do dividendo: ");
		//Guarda o valor digitado pelo usuário na variável dividendo
		int dividendo = input.nextInt();
		//Imprime mensagem para a inserção do segundo valor
		System.out.println("Insira o valor do divisor: ");
		//Guarda o valor digitado pelo usuário na variável divisor
		int divisor = input.nextInt();

		//Verifica se o valor do divisor é igual a zero
		if (divisor == 0) {
			//Imprime o valor -1 caso o divisor seja zero
			System.out.println("-1");
		}
		//Verifica se o valor do cálculo da divisão é negativo
		else if ((dividendo / divisor < 0)) {
			//Imprime o valor 0 caso o resultdo da divisão seja negativo
			System.out.println("Valor encontrado: 0");
		}
		else {
			//Como o divisor não é zero e o cálculo não é negativo, imprime o resultado da divisão
			System.out.println("Valor calculado: " + 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 idéia por de trás do código.

Esta é uma possível solução do problema, e não única. Podemos ter outros passos pra 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?

import java.util.Scanner;

public class DivisaoDeNumeros {

	public static void main(String[] args) {
		//Criamos um objeto Scanner para capturar o que foi digitado
		Scanner input = new Scanner(System.in);
		//Imprime mensagem para a inserção do primeiro valor
		System.out.println("Insira o valor do dividendo: ");
		//Guarda o valor digitado pelo usuário na variável dividendo
		int dividendo = input.nextInt();
		//Imprime mensagem para a inserção do segundo valor
		System.out.println("Insira o valor do divisor: ");
		//Guarda o valor digitado pelo usuário na variável divisor
		int divisor = input.nextInt();

		//Verifica se o valor do cálculo da divisão é negativo
		if ((dividendo / divisor < 0)) {
                        //Imprime o valor 0 caso o resultdo da divisão seja negativo 
                        System.out.println("Valor encontrado: 0");
                }
                //Verifica se o cálculo é positivo
                else if (dividendo / divisor > 0) {
			//Imprime o resultado do cálculo caso o resultado seja positivo
			System.out.println("Valor calculado: " + dividendo / divisor);
		}
		//Como o resultado não é positivo e nem negativo, podemos supor que o divisor é zero
		else {
			//Imprime o valor -1 pois o divisor é zero
			System.out.println("-1");
		}
	}
}

Erro! Veja como não precisamos entender a linguagem/sintaxe pra 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.

#include<stdio.h>
#include<stdlib.h>

int main() {
   //Declaração das variáveis para guardar os valores
   int dividendo;
   int divisor;

   //Imprime mensagem para a inserção do primeiro valor
   printf("Digite o valor do dividendo:");
   //Guarda o valor digitado pelo usuário na variável dividendo
   scanf("%d", &dividendo);

   //Imprime mensagem para a inserção do segundo valor
   printf("\nDigite o valor do divisor:");
   //Guarda o valor digitado pelo usuário na variável divisor
   scanf("%d", &divisor);   

   //Verifica se o valor do divisor é igual a zero
   if (divisor == 0) {
      //Imprime o valor -1 caso o divisor seja zero
      printf("-1\n");
   }
   //Verifica se o valor do cálculo da divisão é negativo
   else if ((dividendo / divisor < 0)) {
      //Imprime o valor 0 caso o resultdo da divisão seja negativo
      printf("Valor encontrado: 0\n");
   }
   else {
      //Como o divisor não é zero e o cálculo não é negativo, imprime o resultado da divisão
      printf("Valor calculado: %d \n", (dividendo / divisor));
   }
   //Pausa a execução
   system("PAUSE");
}

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 do 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 pra modificar os códigos acima, criando outros passos!

Finalizando
Neste artigo vimos a resolução de um problema usando Java e C e a idéia principal é entender o conceito! Entendido o problema e os passos para a resolução dele, traduzí-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.

Nos próximos artigos desta série vamos resolver alguns problemas mais complicados (este foi bem simples, apenas para a introdução) e em breve vou falar sobre assuntos mais específicos, como Pilhas, Filas, Tempo de Algoritmo, etc.

Estes códigos você também pode encontrar em:
Código em Java
Código em C

Abraços!!!

Algoritmos, Parte I – Conceito

Fala Desenvolvedores!!!

Estou começando esta série de artigos pois senti em alguns fóruns que um pessoal gosta bastante de falar sobre Spring, Struts, Hibernate, JSP, JSF, etc, mas acaba 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 muito 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á!

Objetivo da série
O objetivo é simples: 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 o 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 idéia é 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 pra 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
Definição em poucas palavras: 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 pra 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 idéia 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:

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 pra 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 idéia é 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.

Finalizando
Pessoal, este artigo foi somente uma breve introdução sobre o estudo de Algoritmos(que é extenso) e foi também para lembrarmos sobre como podemos dar pequenos passos para a resolução de problemas e não necessariamente utilizando linguagens de programação.

No próximo artigo já vamos resolver alguns problemas clássicos utilizando Java e C, ou seja, estarei supondo que você já conheça um pouco da sintaxe de uma dessas duas linguagens.
Para você que está começando exatamente agora, sugiro dar uma pequena pesquisada sobre a sintaxe da linguagem de sua escolha para aproveitarmos melhor os exemplos que serão mostrados.

E lembro também que mais pra frente falaremos sobre um assunto que confunde bastante a cabeça de alguns, que são Pilhas, Filas e Pesquisa de registros, além do Cálculo do Tempo destes Algoritmos, ou seja, os “nem tão iniciantes” poderão tentar resolver os problemas também!

Abraços pessoal!!!