quarta-feira, 23 de janeiro de 2013

Matrizes em Java

Olá pessoal, estava dando uma olhada em minhas publicações e percebi que estava faltando explicar sobre matrizes na linguagem Java. Bom vamos lá então.
Dica: Antes de ler sobre Matrizes em Java leia esse post que fala sobre vetores (arrays unidimensionais).


Cotidiano com matriz

Matriz por definição é um array multidimensional, ou seja, um array de várias dimensões. Para aplicações em nível de softwares comerciais dificilmente você irá empregar o uso de mais de duas dimensões em um array. Para declarar um array de 2D (duas dimensões) em Java fazemos:

int[][] array2D = new int[2][2];

Nesse exemplo foi declarado um array de "quadrado" de duas linhas e duas colunas. Um array 2D pode ser de vários tipos: String, float, int, double, porém, ele deve ser heterogêneo não podendo armazenar dados de tipos diferentes. Se o array foi declarado do tipo String então suas linhas e colunas devem armazenar somente valores do tipo String.

A solução para armazenar dados de diferentes tipos em matrizes (arrays multidimensionais) é a criação de outras matrizes e fazer a leitura associadamente. Por exemplo, suponha que você tenha que armazenar o nome, endereço, idade e código de um contato. Sabendo que código e idade são tipos inteiros de dados (int) e que nome e endereço são tipos caracteres de dados (String) como armazenar essas informações? Veja:

String[][] caracteres = new String[4][2]; int[][] inteiros = new int[4][2]; caracteres[0][0] = nome; caracteres[0][0] = endereco; inteiros[0][0] = codigo; inteiros[0][1] = idade
Dessa forma conseguimos guardar dados referentes a um mesmo contato em diferentes matrizes de diferentes tipos de dados. Para acessar todas as informações de um determinado contato basta informamos o mesmo número de linha para as duas matrizes, isso retorna todas as informações referentes ao contato procurado.

Vamos imaginar agora que nossa matriz tenha um número muito grande de elementos e que acessar ela índice por índice seria uma tarefa árdua e muito trabalhosa. Para percorrer uma matriz podemos utilizar a estrutura de repetição for. Veja como fica:

for(int i = 0; i < 4; i++) {     for(int j = 0; j < 2; j++) {         System.out.println(caracteres[i][j]);         System.out.println(inteiros[i][j]);     } }

Bom tudo o que foi apresentado até agora resolve muito bem o seu problema quando você conhece previamente o tamanho que a matriz tem. Mas e se você não souber o tamanho do matriz?

Quando não sabemos o tamanho da matriz o código fica um pouco mais complexo, mais nada que chega a assustar. Em Java podemos declarar o array sem fornecer um tamanho para ele, veja:

int[][] inteiros;
O que fizemos acima foi dizer a JVM que teremos um Array de duas dimensões, porém, não construímos esse array ainda portanto ele não pode ser utilizado. Agora devemos obter o tamanho que nosso array deve ter para então criarmos e utilizarmos ele. Veja o exemplo:

int r = (int) (Math.random()*100); //gera um número aleatório entre 0 e 99 inteiros = new int[r][r];

Beleza e agora para percorrermos o array devemos utilizar o tamanho armazenado em r, ou podemos utilizar um método para descobrir qual é esse tamanho. Para descobrir quantas linhas e colunas uma array multidimensional tem utilizamos o método length, veja:

inteiros.length; //retonar o número de linhas
inteiros[0].length; //retorna o número de colunas

Agora veja como podemos percorrer a matriz utilizando o método length:

for(int i = 0; i < inteiros.length; i++) {     for(int j = 0; j < inteiros[i].length; j++) {         System.out.println(inteiros[i][j]);     } }

Lembrando que para exibir somente a linha ou coluna de uma matriz podemos deixar o número fixo no índice e usar o for para percorrer dinamicamente os demais índices do array, veja:

//exibindo todos os elementos da linha 0 for(int coluna = 0; coluna < inteiros[0].length; coluna++) {     System.out.println(inteiros[0][coluna]); }
//exibindo todos os elementos da coluna 1 for(int linha = 0; linha < inteiros.length; linha++) {     System.out.println(inteiros[linha][1]); }


Pessoal seguem dois desafios abaixo para tentarem solucionar, tentam solucionar e dúvidas postem comentários. Vou postar o link com a resolução dos exercícios mais tarde. Abraço a todos!

Dica: comentar código é uma boa prática de programação.

  1. Crie um programa Java que receba duas matrizes como entrada de dimensões N:M (importânte que sejam tamanhos genéricos, usuário deve definir). Ao termino da leitura programa deve calcular a multiplicação entre essas matrizes (produto de matrizes).
  2. (Desafio) Crie um programa Java que seja capaz de ler informações de N funcionários de uma empresa, o programa deve armazenar: Nome (String), Apelido (String), Idade (int), código (int). Já sabemos que matrizes em Java são homogêneas portanto só conseguem guardar um tipo único de dados. O programa deve exibir os dados dos N funcionários em ordem crescente por idade.

domingo, 13 de janeiro de 2013

Praticidade em foco: Python + SQLite

Introdução

SQLite é uma biblioteca Open Source escrita em linguagem C, que implementa um interpretador SQL, e provê funcionalidades de banco de dados, usando arquivos, sem a necessidade de um processo servidor separado ou de configuração manual.

A vantagem mais significativa de usar o SQLite é a praticidade, principalmente no uso em aplicativos locais para desktops, aonde usar um SGBD convencional seria desnecessário e complicado de manter. (texto retirado do livro Python para desenvolvedores).

# -*- coding: utf-8 -*- import sqlite3 # Cria uma conexão e um cursor con = sqlite3.connect('contatos.db') cur = con.cursor() # Cria uma tabela sql = 'create table contatos '\ '(id integer primary key, '\ 'nome varchar(100), '\ 'email varchar(100))' cur.execute(sql) # sentença SQL para inserir registros sql = 'insert into contatos values (null, ?, ?)' # Dados recset = [('guilherme', 'gui@gui.com'), ('giovanna', 'gii@gii.com')] # Insere os registros for rec in recset: cur.execute(sql, rec) # Confirma a transação con.commit() # Seleciona todos os registros cur.execute('select * from contatos') # Recupera os resultados recset = cur.fetchall() # Mostra for rec in recset: print '%d: %s(%s)' % rec # Fecha a conexão con.close()

Esse é o jeito tradicional de se conectar a um banco de dados utilizando o Python puro. Também podemos utilizar ferramentas ORM para facilitar e agilizar nosso trabalho. Uma excelente ferramenta ORM para Python é a SQLAlchemy, em posts futuros abordarei mais sobre esse incrível framework.

Programando em Java - parte 13

Polimorfismo

Polimorfismo, é uma palavra de origem grega que siginifica "muitas formas". Em POO polimorfismo é a capacidade de objetos de classes diferentes responderem a mesma mensagem de diferentes maneiras.

Vejamos o seguinte exemplo:
Uma empresa de tecnologia resolveu desenvolver um controle universal que poderá controlar qualquer tipo de aparelho eletrônico, cada aparelho atende os comandos especificos definidos por ele. 

Segundo Jun Matsumoto (gerente da empresa) o controle remoto teria vários botões, sendo que todos eles seriam úteis para todos os aparelhos. Assim quando o usuáiro clicasse no botão ligar, todos os aparelhos que estivesse em um raio de 1,5m ligariam. 

Jun ainda acrescenta que cada aparelho se comportará de acordo com a sua função, ou seja, quando solicitamos via controle que os aparelhos liguem cada um ligara de acordo com as suas caracteríscas já que a geladeira liga de uma forma, o forno microondas de outra e assim em diante.
Repare que os aparelhos respondem ao mesmo sinal de formas diferentes, temos aqui um caso de POLIMORFISMO.


Tipos de polimorfismo

O polimorfismo pode ser classificado de 3 maneiras:
  1. Sobrecarga ( se você ainda não leu de uma paradinha e aproveite para esclarecer suas dúvidas)
  2. Sobreposição ( leia a seção Reecrita de Métodos, aproveite esse momento caso você não tenha lido )
  3. Inclusão
Vamos implementar o código e em seguida explicaremos o conceito de inclusão.

public class Aparelho { public void ligar () { System.out.println ("Ligar aparelho"); } }
public class TV extends Aparelho { public void ligar () { System.out.println ("Ascender tela"); } }
public void Torradeira extends Aparelho { public void ligar () { System.out.println ("Ascender luz on"); } }
public void Microondas extends Aparelho { public void ligar () { System.out.println ("Piscar luz de ativo"); } }
public class Controle { private Aparelho aparelho; public Controle (Aparelho aparelho) { this.aparelho = aparelho; } public void ligar () { aparelho.ligar (); } }
public class Principal { public static void main (String[] args) { Tv tv = new Tv ()/ Controle controle = new Controle (tv); controle.ligar (); } }

Polimorfismo de inclusão usa a capacidade de substituição da Herança, de uma classe mãe por qualquer classe descendente, para permitir um comportamento polimórfico nos métodos que usam a classe mãe.
No exemplo visto a cima,veja a classe Principal,  onde criamos um objeto do tipo TV e outro do tipo Controle, nós utilizamos o comportamento polimórfico do polimorfismo de inclusão. Fizemos isso quando substituímos a classe Aparelho (mãe) pela classe TV (filha) dentro da classe Controle. Assim, o atributo interno do tipo Aparelho da classe Controle pode receber qualquer objeto que seja de uma classe filha de Aparelho.

Arquivo de I/O em Python

Introdução

Escrever em arquivos é uma necessidade que muitas vezes você vai se deparar, seja para criar um arquivo de log ou mesmo para persistir as informações de seu sistema. A manipulação de arquivos em Python ocorre de uma maneira bem simples e tranquila, com apenas 2 linhas de código podemos criar e escrever ou ler um arquivo. 

Criando um arquivo em Python

O função open retorna um objeto de arquivo, e é frequentemente utilizada com dois argumentos: open (arquivo_nome, modo_operacao).

f = open ('arquivo.txt', 'w') f.close ()
O primeiro parâmetro é o nome do arquivo que será aberto, o segundo parâmetro é o modo de operação que esse arquivo será aberto:
  • w : Será aberto para edição (write). Quando um arquivo é aberto com 'w' todo os texto que o arquivo tinha antes de ser aberto é perdido.
  • r : Será aberto para leitura (read). Quando um arquivo é aberto com 'r' é possível acessar todo o seu conteudo para leitura, porém, nada pode ser inserido ou removido.
  • r + : abre o arquivo tanto para leitura quanto para escrita.
  • a : Funciona como o 'w', porém, não apaga o texto que havia no arquivo antes do mesmo ser aberto.

Leitura arquivos

Para ler o conteúdo de um arquivo utilizamos f.read (size), que lê todos os dados do arquivo e retornam esses dados como uma string. Se o parâmetro for omitido então todo os conteúdo do arquivo será carregado, caso contrário só será carregado o tamanho em bytes do valor passado por parâmetro. Se o fim do arquivo for atingido f.read () irá retornar um arquivo vazio.

Para ler uma única linha do arquivo utilizamos o comando f.readline (). Se f.readline () retornar uma linha vazia o arquivo acabou.

Também é possível retornar todas as linhas do arquivo com o comando f.readlines (), você ainda pode passar por parâmetro o valor em bytes que deseja carregar (ler) do arquivo. Se o valor for omitido todo o conteúdo do arquivo será omitido.

Ainda na leitura de arquivos podemos utilizar o comando for para realizar essa tarefa. Utilizá-lo é mais eficiente, rápido e resulta em código mais simples.

f = open ('notas.txt', 'r') for line in f: print line f.close ()

Escrita de arquivos

Para escrever algo em um arquivo podemos utilizar o comando f.write ('Guilherme Arthur de Carvalho'). Esse método escreve o conteúdo da string para o arquivo e retorna None.
Como o write só escreve objetos do tipo string, se desejar escrever algo que não seja string é necessário converter o valor para string. Lembrando que quando abrimos um arquivo no modo de operação w todo o conteúdo que existia antes no arquivo é apagado.

Se você deseja apenas adicionar texto para seu arquivo, ou seja, concatenar informações abra ele no modo de operação 'a'.

Laços For e While em Python

Introdução

Laços de repetição são usados para repetir código N vezes dentro de um programa. Em Python temos dois comandos para realizar uma repetição, podemos dizer que usamos um deles quando sabemos a quantidade de iterações (loops) que o código irá fazer, e o outro quando essa quantidade é desconhecida.

For

É a estrutura de repetição mais usada no Python. A instrução aceita não só sequências estáticas, mas também sequências geradas por iteradores. Iteradores são estruturas que permitem iterações, ou seja, acesso aos itens de uma coleção de elementos, de forma sequencial.

Podemos utilizar o comando break para interromper o laço e o comando continue para passar para próxima iteração. Podemos adicionar uma condição else fazendo assim o código presente no else ser executado quando o comando for acabar, o else não será executado se o laço for interrompido pelo comando break.

soma = 0 for i in range (1,10): soma += soma print soma

While

Executa um bloco de código atendendo a uma condição, podemos definir o comando While como um if que repete. Então enquanto a condição que está sendo verificada pelo comando while for satisfeita, o bloco de código presente em seu interior será executado.


i = 0 while (i < 10): print i

O laço while é recomendado quando não sabemos ao certo quantas vezes o comando deve se repetir.

Sintaxe do Python

Introdução

Python é uma linguagem muito produtiva, com poucas linhas de código você pode codificar coisas muito interessantes. Para programar em Python não precisamos usar ponto e vírgula, chaves e outros tantos caracteres de marcação que são comumente esquecidos quando estamos codificando. Isso faz com que o índice de erros seja muito menor facilitando assim o nosso trabalho.

Comentários

Para comentar códigos em Python temos de usar o caractere "jogo da velha" #. Essa é a única forma que temos para comentar códigos na linguagem Python. Qualquer texto adicionado depois desse caractere será ignorado, é válido ressaltar que esse comentário é de linha, ou seja, ele é valido somente na linha em que foi inserido.

Em Python temos os comentários funcionais, que podem ser utilizados para alterar a codificação do arquivo fonte do programa. Se faz necessário alterar a codificação do arquivo do programa para que o mesmo suporte caracteres que não estão presentes na língua inglesa. Exemplo de uso: #-*- encoding: utf-8 -*-.

Comentários funcionais servem também para definir o interpretador que será utilizado para rodar o programa em sistemas UNIX. Exemplo de uso: #!/usr/bin/env.

#!/usr/bin/env #-*- encoding: utf-8 -*- #acima temos um exemplo de comentário funcional, e eu sou um comentário print 21/3 #exemplo de quebra de linha a = 5 + 10 \ - 10 print a

Blocos

Na maioria das linguagens os blocos são delimitados por chaves (Java, C++, C#), quando não os blocos são delimitados por palavras chaves (Delphi, VB, Pascal). Em Python os blocos são delimitados por tabulação (endentação) por padrão usamos 4 espaços. Com essa regra além de deixar o código mais enxuto também deixa-o organizado, pois se ele não estiver endentado o interpretador não irá executar o código.

A linha anterior ao bloco, ou seja, onde ele está contido termina com dois pontos. E pode ser uma estrutura de controle da linguagem ou uma declaração de uma nova estrutura.


a = 10 if a%2 == 0: print "par" else print "impar"

sábado, 12 de janeiro de 2013

Porque usar python?

Introdução

Quando iniciamos na área de TI nossa primeira escolha é saber de fato em que caminho queremos seguir. Quando decidimos isso ainda temos uma série de escolhas que vamos ter que fazer ao longo de nossas vidas profissionais. Uma dúvida clássica entre os desenvolvedores de software é "Qual é a melhor linguagem de programação". Assim como aquela velha discussão de "Qual é o melhor sistema operacional", a melhor linguagem de programação não existe, o que existe são problemas que cada uma resolve de um jeito diferente isso as tornam boas, mas ao mesmo tempo pode ser um ponto negativo se olharmos de outra perspectiva. Hoje vou falar de Python, uma linguagem que não é a melhor de todas e muito menos à que vai te deixar rico ou resolver todos os seus problemas. Se você é muito fã de C/C++, Java, C# ou derivados que fique claro que eu não estou comparando Python com nenhuma delas, apenas estou mostrando as qualidades que ela possui Ok? Vamos lá!

Qualidade de software

Para muitos, o foco do Python sobre legibilidade, coerência e qualidade do software em geral distingue-se de outras ferramentas no mundo de scripts. Python foi criado para ser legível, e portanto códigos escritos em python são reutilizáveis e sustentáveis  muito mais do que em linguagens tradicionais. A uniformidade de código do Python é fácil de entender, mesmo que você não conheça a linguagem. Além disso Python tem apoio profundo para reutilização de software, conta com mecanismos mais avançados tais como programação orientada a objeto (POO).

Produtividade

Python é mais produtivo do que linguagens compiladas ou esticamente tipadas, tais como C/C++ e Java. Os código escritos em Python geralmente equivalem a um terço ou até mesmo um quinto do tamanho de códigos escritos em C/C++ ou Java. Isso representa menos código para debugar e menos código para manter. Os programas escritos em Python também executam simultaneamente, isso ocorre porque o Python é uma linguagem interpretada sem que haja a necessidade de compilar o código a cada nova alteração.

Portabilidade

A maioria dos programas em Python executam inalterados em todas as principais plataformas de computador. A portabilidade do código entre Linux e Windows, por exemplo, geralmente é apenas uma questão de copiar um código de script entre máquinas. Além disso, Python oferece multiplas opções para a codificação de interfaces gráficas, programas de acesso ao banco de dados, desenvolvimento web, e muito mais.

Suporte a bibliotecas

Python vem com uma grande coleção de modelos reutilizáveis e funcionalidade portátil, conhecida como a biblioteca padrão. Está biblioteca suporta uma vasta gama de tarefas em nível de aplicação. Mais por ser aberto o Python possui muitas bibliotecas disponibilizadas por terceiros que são projetas para trabalhar especificamente com alguns tipos de dados e informações, alguns bons exemplos são: 
  • NumPy: Essa biblioteca foi desenhada para a manipulação de vetores e matrizes. Ela é tão poderosa quanto a ferramenta Matilab.
  • SQLAlchemy: biblioteca de mapeamento objeto-relacional SQL, provém "de uma suíte completa do conhecido nível-empresarial de padrões de persistência, desenvolvido para eficiência e alta performance no acesso à banco de dados.
  • Twisted: Framework completo para trabalhar com protocolos de redes.

Integração

Scripts Python pode facilmente comunicar-se com outras partes de um aplicativo, usando uma variedade de mecanismos de integração. Tais integrações permitem que o Python possa ser utilizado como um personalização do produto e da ferramenta de extensão. Hoje, o código Python pode invocar C e Bibliotecas C++, pode ser chamado de códigos escritos em C e C++ (CPython), pode se integrar com Java (Jython) e. NET (IronPython), pode comunicar através de quadros como COM, pode ser interface com dispositivos mais portas seriais, e pode interagir em redes com SOAP, XML-RPC e CORBA.

Satisfação

Devido a sua facilidade e seu conjunto de ferramentas, Python pode fazer o ato de programar mais prazeroso do que frustrante. Embora isso possa ser um benefício inatingível. Seu efeito sobre a produtividade é um trunfo importante.

quarta-feira, 9 de janeiro de 2013

Estruturas de dados - Resolução da lista 7 (Listas Encadeadas)

Olá pessoal esse post tem a resolução dos exercícios do 1 - 10. O exercício 11 postarei mais tarde. Qualquer duvida comentem, ok? A outra coisa se faz necessário usar o arquivo cabeçalho que eu criei (utils.h). Eu postei ele aqui no blog http://programando-ads.blogspot.com.br/2013/01/lista-de-exercicios-eda-listas.html.

Exercicio 1.
#include #include #include "utils.h" int lst_comp (Lista *l) { int i = 0; while (l != NULL) { i++; l = l->prox; } return i; } int main(void) { Lista *l; l = lst_cria (); l = lst_insere (l, 20); l = lst_insere (l, 20); l = lst_insere (l, 20); l = lst_insere (l, 20); l = lst_insere (l, 20); printf ("\ncomprimento da lista: %d \n", lst_comp (l)); return 0; }
Exercício 2.
#include #include #include "utils.h" int lst_maiores (Lista *l, int n) { Lista *p = l; int x = 0; for (p = l; p != NULL; p = p->prox) { if (p->value > n) x++; } return x; } int main(void) { Lista *l; l = lst_cria (); l = lst_insere (l, 20); l = lst_insere (l, 120); l = lst_insere (l, 40); l = lst_insere (l, -100); l = lst_insere (l, 13); system ("clear"); printf ("\n Numero de elementos maiores que %d = %d\n", 20, lst_maiores (l, 20)); printf ("\n Numero de elementos maiores que %d = %d\n", 10, lst_maiores (l, 10)); printf ("\n Numero de elementos maiores que %d = %d\n", 0, lst_maiores (l, 0)); printf ("\n Numero de elementos maiores que %d = %d\n", 240, lst_maiores (l, 240)); printf ("\n Numero de elementos maiores que %d = %d\n", 2, lst_maiores (l, 2)); return 0; }
Exercício 3.
#include #include #include "utils.h" int main(void) { Lista *l; l = lst_cria (); l = lst_insere (l, 20); l = lst_insere (l, 120); l = lst_insere (l, 40); lst_imprime (l); Lista *y = lst_ultimo (l); printf ("\nUltimo elemento da lista %d\n", y->value); return 0; }
Exercício 4.
#include #include #include "utils.h" Lista *lst_concatena (Lista *l1, Lista *l2) { Lista *p = NULL; p = lst_ultimo (l1); p->prox = l2; } int main (void) { Lista *l1; Lista *l2; l1 = lst_cria (); l1 = lst_insere (l1, 1); l1 = lst_insere (l1, 2); l1 = lst_insere (l1, 3); l2 = lst_cria (); l2 = lst_insere (l2, 4); l2 = lst_insere (l2, 5); l2 = lst_insere (l2, 6); Lista *p = lst_concatena (l1, l2); printf ("Valor: %d\n", p->prox->value); return 0; }
Exercício 5. #include #include #include "utils.h" Lista *lst_retira_n (Lista *l, int n) { Lista *p =NULL; while (l != NULL) { if (l->value != n) p = lst_insere (p, l->value); l = l->prox; } return p; } int main (void) { Lista *l; l = lst_cria (); l = lst_insere (l, 10); l = lst_insere (l, 50); l = lst_insere (l, 10); l = lst_insere (l, 50); l = lst_insere (l, 10); l = lst_retira_n (l, 50); lst_imprime (l); return 0; }
Exercício 6.
#include #include #include "utils.h" Lista *lst_separa (Lista *l, int n) { Lista *p = NULL; while (l != NULL && l->value != n) l = l->prox; l = l->prox; while (l != NULL) { p = lst_insere (p, l->value); l = l->prox; } return p; } int main (void) { Lista *l; l = lst_cria (); l = lst_insere (l, 10); l = lst_insere (l, 50); l = lst_insere (l, 60); l = lst_insere (l, 70); l = lst_insere (l, 80); printf ("\nOcorrencia: 50\n"); printf ("\nLista Original\n"); lst_imprime (l); printf ("\n\nLista separada:"); l = lst_separa (l, 50); lst_imprime (l); return 0; }
Exercício 7. #include #include #include "utils.h" Lista *lst_merge (Lista *l1, Lista *l2) { Lista *p = NULL; Lista *p1 = NULL; Lista *p2 = NULL; for (p1=l1, p2=l2; p1 != NULL && p2 != NULL; p1=p1->prox, p2=p2->prox) { p = lst_insere (p, l2->value); l2 = l2->prox; p = lst_insere (p, l1->value); l1 = l1->prox; } return p; } int main (void) { Lista *l1; Lista *l2; l1 = lst_cria (); l1 = lst_insere (l1, 1); l1 = lst_insere (l1, 2); l1 = lst_insere (l1, 3); l2 = lst_cria (); l2 = lst_insere (l2, 4); l2 = lst_insere (l2, 5); l2 = lst_insere (l2, 6); Lista *p; p = lst_merge (l1, l2); lst_imprime (p); return 0; }
Exercício 8.
#include #include #include "utils.h" Lista *lst_inverte (Lista *l) { Lista *p; Lista *aux=NULL; p=l->prox; l->prox=NULL; while(p!=NULL) { aux=p->prox; p->prox=l; l=p; p=aux; } return l; } int main (void) { Lista *l; l = lst_cria (); l = lst_insere (l, 10); l = lst_insere (l, 20); l = lst_insere (l, 30); puts ("Matriz Original"); lst_imprime (l); puts ("\nMatriz Invertida"); l = lst_inverte (l); lst_imprime (l); return 0; }
Exercício 9.
#include #include #include "utils.h" int lst_igual (Lista *l1, Lista *l2) { for (l1, l2; l1 != NULL && l2 != NULL; l1 = l1->prox, l2 = l2->prox) { if (l1->value != l2->value) return 0; } return 1; } int main (void) { Lista *l1, *l2; l1 = lst_cria (); l1 = lst_insere (l1, 10); l1 = lst_insere (l1, 20); l2 = lst_cria (); l2 = lst_insere (l2, 1); l2 = lst_insere (l2, 20); if (lst_igual(l1, l2)) printf ("\nAs listas são iguais!\n"); else printf ("\nAs listas são diferentes\n"); return 0; }
Exercício 10.
#include #include #include "utils.h" Lista *lst_copia (Lista *l) { Lista *p = l; Lista *y = NULL; while (p != NULL) { y = lst_insere (y, p->value); p = p->prox; } return y; } int main (void) { Lista *l; l = lst_cria (); l = lst_insere (l, 20); l = lst_insere (l, 100); l = lst_insere (l, 30); l = lst_insere (l, 20); l = lst_insere (l, 20); Lista *y; y = lst_copia (l); system ("clear"); lst_imprime (y); return 0; }

terça-feira, 8 de janeiro de 2013

Lista de exercícios EDA - Listas encadeadas

Esse arquivo cabeçario eu criei com base nos métodos de exemplos mostrados no livro "Introdução a Estruturas de Dados - José Lucas Rangel.

Para inseri-lo em seu programa C, basta fazer a cópia do arquivo e salvar com extensão .h (utils.h). Depois basta incluir ele no código fonte que deseja utilizar com o comando #include. Exemplo:

#include <stdio.h>
int main (void) {
    Lista *l;
    l = lst_cria ();
    l = lst_insere (l, 2000);
    lst_libera (l);
    return 0;
}


Curtam meu blog pô, e compartilha também :D!! Até mais!

typedef struct lista {
int value;
struct lista *prox;
} Lista;

/* função de criação: retorna uma lista vazia */
Lista *lst_cria (void) {
return NULL;
}

/* inserção no início: retorna lista atualizada */
Lista *lst_insere (Lista *l, int i) {
Lista *novo = (Lista *) malloc(sizeof(Lista));
novo->value = i;
novo->prox = l;
return novo;
}

/* função imprime:  imprime valores dos elementos */
void lst_imprime (Lista *l) {
Lista *p; /* variável auxiliar para percorrer a lista */

for (p = l; p != NULL; p = p->prox) {
printf ("Value = %d\n", p->value);
}
}

/* função vazia: retorna 1 se vazia ou 0 se não vazia */
int lst_vazia (Lista *l) {
if (l == NULL)
return 1;
else
return 0;
}

/* função busca: busca o elemento na lista */
Lista * lst_busca (Lista * l , int v) {
Lista * p;
for (p = l; p != NULL; p = p->prox) {
if (p->value == v)
return p;
}
return NULL; /* não achou o elemento */
}

/* função retirra: retira o elemento da lista */
Lista *lst_retira (Lista *l, int v) {
Lista *ant = NULL; /* ponteiro para o elemento anterior */
Lista *p = l; /* ponteiro para percorrer a lista */

/* procura o valor na lista, guardando o anterior */
while (p != NULL && p->value != v) {
ant = p;
p = p->prox;
}

/* verifica se achou o elemento */
if (p == NULL)
return l; /* não achou: retorna a lista original */

/* retira o elemento */
if (ant == NULL)
/* retira o elemento de inicio*/
l = p->prox;
else
/* retira o elemento do meio da lista */
ant->prox = p->prox;

free (p);
return l;
}

/* função libera: libera o espaço em memória ocupado pela lista */
void lst_libera (Lista *l) {
Lista * p = l;

while (p != NULL) {
Lista * t = p->prox; /* guarda referência para o próximo elemento */
free (p); /* libera a memória apontada por p */
p = t;  /* faz p apontar para o próximo */
}
}

sexta-feira, 7 de dezembro de 2012

Lista 6 de EDA - Estrutura de dados

Lista de estrutura de dados - 6ª lista

Faça um programa que cadastre 50 produtos.
Cada produto deve ser cadastrado com os seguintes dados: código, nome e preço.

1. Use 3 métodos de ordenação diferentes, liste todos os dados na seguintes formas:
  • Ordem crescente de código;
  • Ordem decrescente de preço;
  • Ordem alfabética de nome;
 2. Verifique no vetor ordenado:
  • O produto mais barato, se houver mais de um com o mesmo preço, mostrá-los.
  • Calcule e mostre a diferença entre os preços do produto mais barato e do mais caro.
3. Mostre quantas comparações devem ser feitas para encontrar um produto pelo código usando:
  • Busca sequencial;
  • Busca binária;
Resolução:
#include <stdio_ext.h>
#include <stdlib.h>
#include <string.h>

#define TAMANHO 50

typedef struct
{
    int codigo;
    char nome[80];
    float preco;
} Produto;

/* Protótipos das funções */
void inicializa_vetor (Produto**);
void menu (Produto**, int*);
void cadastrar (Produto**, int*);
void listar (Produto**, int*);
void ordenacao (Produto**, int*, int);
void bubblesort(Produto**, int*);
void selectionsort(Produto**, int*);
void insertionsort(Produto**, int*);
float buscarMaisBarato(Produto**, int*, int);
float buscarMaisCaro(Produto**, int*, int);
int buscaLinear(Produto**, int*, int);
int buscaBinaria(Produto**, int*, int);

int
main (void)
{
    Produto *p[TAMANHO];
    int qtde=0; // quantidade de elementos cadastrados em meu vetor

    inicializa_vetor(p);
    menu(p, &qtde);

    return 0;
}

void
inicializa_vetor(Produto **p)
{
    int i;
    for (i=0; i<TAMANHO; i++) p[i]=NULL;
}

void
menu(Produto **p, int *qtde)
{
    int opcao, ordenado=0;

    while (1)
    {
        printf ("\nInforme a opção desejada\n");
        puts ("1 - Cadastrar");
        puts ("2 - Listar");
        puts ("3 - Ordenar");
        puts ("4 - Produto mais barato");
        puts ("5 - Diferença entre produtos");
        puts ("6 - Busca Linear");
        puts ("7 - Busca Binária");
        puts ("8 - Sair");
        printf (".: ");
        scanf ("%d", &opcao);

        switch (opcao)
        {
            case 1:
                cadastrar(p, qtde);
                ordenado=0;
            break;
            case 2:
                listar(p, qtde);
            break;
            case 3:
                system ("clear");
                puts ("--- Métodos de ordenação ---");
                puts ("1 - Bubble Sort (código)");
                puts ("2 - Selection Sort (preço)");
                puts ("3 - Insertion Sort (alfabética)");
                int ordem;
                scanf ("%d", &ordem);

                if (ordem==1) ordenado=1;

                ordenacao(p, qtde, ordem);
            break;
            case 4:
                system ("clear");
                buscarMaisBarato(p, qtde, 1); // despresando o retorno
            break;
            case 5:
                system ("clear");
                printf ("Mais caro custa = %.2f\nMais barato custa = %.2f\nDiferença = %.2f \n", buscarMaisCaro(p, qtde, 0), buscarMaisBarato(p,qtde,0),
                        buscarMaisCaro(p,qtde,0) -buscarMaisBarato(p,qtde,0));
            break;
            case 6:
                printf ("\nInforme o código.: ");
                int codigo;
                scanf ("%d", &codigo);
                system ("clear");
                printf ("\nForam feitos %d loop(s) para encontrar o número %d.\n", buscaLinear(p, qtde, codigo), codigo);
            break;
            case 7:
                printf ("\nInforme o código.: ");
                scanf ("%d", &opcao);
                if(ordenado)
                {
                    system ("clear");
                    printf ("\nForam feitos %d loop(s) para encontrar o número %d.\n", buscaBinaria(p, qtde, opcao), opcao);
                }
                else puts ("\n -- Primeiro ordene o vetor pelo código antes de realizar a busca binária! -- ");
            break;
            case 8:
                system ("clear");
                puts ("Programa encerrado!");
                exit(0);
            break;
        }
    }
}

void
cadastrar(Produto **p, int *qtde)
{
    int codigo;
    printf ("\nEntre com o código do produto.: ");
    scanf("%d", &codigo);

    int i;
    for (i=0; i<*qtde; i++)
        if (p[i]->codigo == codigo) break;

    if (i != *qtde)
    {
        system ("clear");
        printf ("\n\n--- Esse Código já está cadastrado! ---\n\n");
    }
    else
    {
        // variável qtde diz o indice que o meu vetor deve inserir o novo registro
        p[*qtde] = (Produto*) malloc (sizeof(Produto));
        p[*qtde]->codigo = codigo;
        __fpurge (stdin);
        printf ("\nEntre com a descrição do produto.: ");
        gets (p[*qtde]->nome);
        printf ("\nEntre com o valor do produto.: ");
        scanf ("%f", &p[*qtde]->preco);
        *qtde = *qtde + 1; // incrementa a quantidade de produtos inseridos em meu vetor
        system ("clear");
        puts ("Produto inserido com sucesso!");
    }
}

void
listar(Produto **p, int *qtde)
{
    system ("clear");
    puts ("--- Lista de produtos ---");
    int i;
    for (i=0; i<*qtde; i++)
        printf ("\nCódigo.: %d \tNome.: %s \tPreço.: %.2f\n", p[i]->codigo, p[i]->nome, p[i]->preco);
}

void
ordenacao(Produto **p, int *qtde, int ordem)
{
    if (ordem == 1) bubblesort(p, qtde);
    else if (ordem == 2) selectionsort(p, qtde);
    else if (ordem == 3) insertionsort(p, qtde);
    else
    {
        system ("clear");
        puts ("--- Opção não cadastrada ---");
    }
}

void
bubblesort(Produto **p, int *qtde)
{
    int i,j;
    Produto *aux;

    for (i=0; i<*qtde; i++)
    {
        for (j=0; j<*qtde; j++)
        {
            if (p[i]->codigo<p[j]->codigo)
            {
                aux = p[i];
                p[i] = p[j];
                p[j] = aux;
            }
        }
    }
    puts ("-- Vetor ordenado com sucesso pelo método BUBBLE SORT! -- \n");
}

void
selectionsort(Produto **p, int *qtde)
{
    int i,j;
    Produto *aux;

    for (i=0; i<*qtde; i++)
    {
        for (j=i; j<*qtde; j++)
        {
            if (p[i]->preco < p[j]->preco)
            {
                aux = p[i];
                p[i] = p[j];
                p[j] = aux;
            }
        }
    }
    puts ("-- Vetor ordenado com sucesso pelo método SELECTION SORT! -- \n");
}

void
insertionsort(Produto **p, int *qtde)
{
    int i,j;
    Produto *eleito;

    for (j=1; j<=*qtde-1; j++)
    {
        eleito = p[j];
        i = j-1;

        while (i>=0 && (strcmp(eleito->nome, p[i]->nome) == -1))
        {
            p[i+1] = p[i];
            i--;
        }
        p[i+1] = eleito;
    }
    puts ("-- Vetor ordenado com sucesso pelo método INSERTION SORT! -- \n");
}

float
buscarMaisBarato(Produto **p, int *qtde, int listar)
{
    int i, index=0;
    float v=p[index]->preco;
    for (i=1; i<*qtde; i++)
    {
        if (p[i]->preco<v)
        {
            v=p[i]->preco;
            index=i;
        }
    }

    if (listar)
    {
        puts ("\n -- Produto(s) mais barato(s) da base de dados --");

        for (i=0; i<*qtde; i++)
        {
            if (v==p[i]->preco)
            {
                printf ("\nCódigo.: %d", p[i]->codigo);
                printf ("\nNome.: %s", p[i]->nome);
                printf ("\nPreço.: %.2f", p[i]->preco);
            }
            puts("");
        }
    }
    return v;
}

float
buscarMaisCaro(Produto **p, int *qtde, int listar)
{
    int i, index=0;
    float v=p[index]->preco;
    for (i=1; i<*qtde; i++)
    {
        if (p[i]->preco>v)
        {
            v=p[i]->preco;
            index=i;
        }
    }

    if (listar)
    {
        puts ("\n -- Produto(s) mais Caro(s) da base de dados --");
        for (i=0; i<*qtde; i++)
        {
            if (v==p[i]->preco)
            {
                printf ("\nCódigo.: %d", p[i]->codigo);
                printf ("\nNome.: %s", p[i]->nome);
                printf ("\nPreço.: %.2f", p[i]->preco);
            }
            puts("");
        }
    }
    return v;
}

int
buscaLinear(Produto **p, int *qtde, int codigo)
{
    int i, x=0;
    for (i=0; i<*qtde; i++)
    {
        if (p[i]->codigo == codigo)
        {
            x=1;
            break;
        }
    }
    if (x==0)
        puts ("-- Nenhum registro foi encontrado! --");
    return i;
}

int
buscaBinaria(Produto **p, int *qtde, int codigo)
{
    int esquerda=0, meio, direita=*qtde-1;
    int status=0, x=0;

    while (esquerda <= direita)
    {
        x++;
        meio = (esquerda+direita)/2;
        if (p[meio]->codigo == codigo) status = 1;
        if (p[meio]->codigo < codigo) esquerda = meio + 1;
        else direita = meio - 1;
    }

    if (status == 1)
    {
        printf ("\n \t\t -- Registro número %d", p[meio]->codigo);
        printf ("\n Nome.: %s", p[meio]->nome);
        printf ("\n Preço.: %.2f", p[meio]->preco);
        puts("");
    }
    else
        printf ("\n\t\t -- Nenhum registro foi encontrado!--\n");
    return x;
}

Dúvidas ou sugestões deixe um comentário. Até a próxima!

domingo, 2 de dezembro de 2012

Programando em Java - parte 12

Herança

Na programação orientada a objetos temos o recurso de herança, que nada mais é que abstrair uma classe o mais genericamente possível e escrever outras classes mais especificas aproveitando os comportamentos e atributos da classe genérica. A ideia da herença é aumentar a produtividade na escrita do código e também deixar o código mais limpo, evitando a redundancia de código entre as classes (código repetido).
Como todo conceito da POO não é explicitamente obrigatório o uso de herança em seu código também não, porém, não usá-lo significa quebra conceitual.

Uma classe que faz tudo!

Muitos programadores acham que é beneficio criar uma classe que faça completamente tudo em seu sistema. Não há problema algum em declarar todas as funcionalidades de um sistema dentro de uma classe. No entanto, seu código fica muito mais complexo e a dificuldade de manutenção aumenta muito. Vejamos como poderiamos resolver o mesmo problema primeiramente sem utilizar a herança, depois utilizando a herança de forma errada e por fim aplicando a herança corretamente.

Classe animal.java


Olá meu nome é Juca! 
Preciso de um sistema que cadastre meus bichos de estimação. Sabe senhor programador eu sou um cara muito versátil quando se fala de animais, eu gosto de: cachorros, gatos, lagartos, passáros, tartarugas .. Preciso de um sistema bom, barato e que me entregue o mais rápido possível OK?!

Bom, muitas vezes você vai se deparar com os Jucas da vida, e a pergunta é como os maus programadores fariam esse sistema? Será que eles usariam Herança? Vamos para o exemplo:

public class BichoEstimacao {
// geral
private Animal animal;
private String nome;
private Date aniversario;
// mamiferos
private String corPelo;
private int nroGlandulasMamaria;
// repteis
private float temperaturaCorporal;
private String corEscama;
// métodos
}

Bom apesar de resolver todos os nossos problemas quanto a modelagem do sistema, programar todas as funcionalidades em apenas uma classe pode dificultar o desenvolvimento. Supondo que dois ou mais desenvolvedores são responsáveis pela implementação dos bichos de estimação, provavelmente eles modificariam a mesma classe em paralelo. Além disso, os desenvolvedores ficariam  confusos ao abrirem o código dessa classe.

Uma classe para cada animal

Para modelar melhor os animais, evitando uma quantidade grande de atributos e métodos desnecessários, criaremos uma classe para cada Animal.

public class Gato {
    // geral
    private Animal animal;
    private String nome;
    private Date aniversario;
    // gato
    private String corPelo;
    private int nroGlandulasMamarias;
    private String raca;
}


public class Tiu {
    // geral
    private Animal animal;
    private String nome;
    private Date aniversario;
    // tiu
    private String corEscama;
    private float temperaturaCorpo;
    private boolean chocando;
}

Criar uma classe para cada animal torna o sistema mais flexível, pois qualquer alteração em um determinado serviço não causará efeitos colaterais nos outros. Porém, essas classes apresentam redundância de código e sabemos que a herança veio para abolir isso! E pior, qualquer alteração que seja comum a todos os animais deverá ser implementada classe por classe. Isso quer dizer que ainda estamos errando em alguma coisa.

Uma classe genérica e várias específicas

Na modelagem dos animais do sistema do Juca, podemos aplicar o conceito de Herança. A ideia consiste em reutilizar o código de uma classe em N classes.
Aplicando herança a esse sistema, vamos ter uma classe BichoEstimacao com todos os atributos e métodos comuns à um animal de estimação, e vamos ter uma classe mais específica detalhando as caracteristicas e comportamentos que cada animal possui.
As classes Gato e Tiu seriam "relacionadas" a classe BichoEstimacao para poder reaproveitar o seu código já definido. Veja a representação UML abaixo:


Os objetos das classes específicas Gato e Tiu possuirão tanto os atributos e métodos definidos em suas respectivas classes quanto os definidos na classe BichoEstimacao. Dizemos que BichoEstimacao é a classe pai, e a Gato e Tiu são suas classes filhas. 
Para "associar/ligar" uma classe especifica a uma classe genérica em Java, utilizamos o comando extends. Não é necessário redefinir o conteúdo já declarado na classe genérica.

public class BichoEstimacao {
    // geral 
    private Animal animal;
    private String nome;
    private Date aniversario;
}

public class Gato extends BichoEstimacao {
    // gato
    private corPelo;
    private nroGlandulasMamarias;
    private raca;
}

public class Tiu extends BichoEstimacao {
    // tiu
    private String corEscama;
    private float temperaturaCorpo;
    private boolean chocando;
}

As classes filhas podem acessar todos os métodos e atributos de seu pai. Java não dá suporte a herança multipla, ou seja, para a Java um Pai pode ter vários filhos já os filhos são de um único pai. Esse pensamento traduzido para vida real é muito lógico já que um filho tem um único pai biológico e esse pai pode ter vários filhos.

Gato mimo = new Gato();
//chamada a um método da classe BichoEstimacao
mimo.setNome = "Mimo";
//chamada a um método da classe Gato
mimo.setRaca = "Angora";

Calcular idade

Todos os animais possuim uma idade certo? Vamos considerar inicialmente que para todos animais o calculo de idade é o mesmo. Sendo assim poderiamos implementar um método na classe BichoEstimacao para calcular a idade dos animais. Este método será reaproveitado por todas as classes que herdam da classe BichoEstimacao.

public class BichoEstimacao {
// atributos public int calculaIdade(int anoNascimento, int anoAtual) { return anoAtual - anoNascimento; }  }

BichoEstimacao bicho = new BichoEstimacao();
Gato megui = new Gato();
System.out.println("Idade: ", + bicho.calculaIdade(2010,2012));
System.out.println("Idade: ", + megui.calculaIdade(2012,2012));

Reescrita de método

Como sabemos cada animal representa uma idade diferente ao calculo da idade humana, alguns animais possuem um envelhicimento mais tardio e outros mais recentes. Como essa lógica é específica de cada animal devemos implementar esse calculo na classe BichoEstimacao.

class Gato extends BichoEstimacao {
// atributos
public int calcIdadeGato(int anoNascimento, int anoAtual) {
return (anoAtual - anoNascimento) * 7 ;
}

Para os objetos da classe Gato devemos chamar o método calcIdadeGato. Para todos os outros animais devemos chamar o método calculaIdade.

Mesmo assim isso não impederia que o método calculaIdade fosse chamado de um objeto da classe Gato, pois este método é herdado da sua classe Pai BichoEstimacao. Deste modo existe o risco de acidentamente invocarmos o método errado.

O correto é substituir a implementação do método calculaIdade(int anoNascimento, int anoAtual) herdado da classe BichoEstimacao na classe Gato. Para isso, basta escrever o método calculaIdade(int anoNascimento, int anoAtual) também na classe Gato do mesmo jeito que ela foi definida na classe Pai (BichoEstimacao), ou seja, com a mesma assinatura.

class Gato extends BichoEstimacao {
// atributos
public int calculaIdade(int anoNascimento, int anoAtual) {
return (anoAtual - anoNascimento) * 7 ;
}

Os métodos das classes filhas tem prioridade sobre os métodos da classe pai. Se o método chamado existe na classe filha ele será chamado, caso contrário se ele não exister será procurado sua existencia na classe Pai.

Novidade!!! Agora vamos ter canal no Youtube =D

Fala pessoal tudo beleza, estou sumido a correria está forte por aqui. Estou querendo dar um start em um projeto antigo que vem desde o temp...