quarta-feira, 28 de janeiro de 2015

Regex para endereço MAC

Fala aí galera que acompanha o blog Preciso Estudar Sempre, lá vai mais uma dica rápida para quem precisa de uma máscara para campos de texto.

A máscara de hoje valida Mac Address. Porém, você sabe o que é um Mac Address ?

Segundo a Wikipedia um Mac Address é:
Endereço MAC (Media Access Control) é um endereço físico associado à interface de comunicação, que conecta um dispositivo à rede. O MAC é um endereço “único”, não havendo duas portas com a mesma numeração, é usado para controle de acesso em redes de computadores. Sua identificação é gravada em hardware, isto é, na memória ROM da placa de rede de equipamentos como desktops, notebooks, roteadores, smartphones, tablets, impressoras de rede, etc. 
http://pt.wikipedia.org/wiki/Endere%C3%A7o_MAC 

Agora que já sabemos o que é um Mac Address precisamos conhecer seu formato. É formado por um conjunto de 6 bytes separado por dois pontos (“:”) ou hífen (“-”), sendo cada byte representado por dois algarismos na forma hexadecimal, como por exemplo: "01:23:45:67:89:ab". Cada algarismo em hexadecimal corresponde a uma palavra binária de quatro bits, desta forma, os 12 algarismos que formam o endereço totalizam 48 bits.

Possuímos nesse momento o conhecimento do que é um Mac Address e como ele é representado. Então, podemos montar a regex para validação.

 ^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$  

Vamos entender o que montamos ?
  1. ^ e $ -> Os caracteres ^ e $, respectivamente, no início e fim da expressão regular denotam um intervalo fechado, ou seja, o texto que for avaliado só pode conter o mac address.
  2. [0-9a-fA-F]{2} -> Defino um intervalo fechado para o par hexadecimal o qual, aceita números de 0 à 9, letras minúsculas e maiúsculas de "a" à "f". O {2} representa que o intervalo será repetido duas vezes.
  3. : -> Representa o dois pontos do Mac Address.
  4. {5} -> Representa que o par hexadecimal será repetido cinco vezes.
  5. [0-9a-fA-F]{2} -> Representa o mesmo explicado no passo 2, ou seja, o último par hexadecimal.

Agora é usar e partir para o abraço !

Amigos, espero ter ajudado. Caso você tenha alguma dúvida, sugestão ou crítica, deixe aí embaixo nos comentários ou na nossa página do facebook.

Facebook: https://www.facebook.com/precisoestudarsempre/

Referências:
http://pt.wikipedia.org/wiki/Endere%C3%A7o_MAC
Leia Mais ››

segunda-feira, 26 de janeiro de 2015

Dica de ferramenta: Trello

Galera, aqui vai uma dica muito legal de ferramenta para gerenciamento de projetos. Essa ferramenta é o Trello. Ela é muito boa, muito fácil de usar. Eu recomendo. Nela você pode criar um board, adicionar cards nela. Nesses cards você pode incluir pessoas, datas, anexos. Ele é responsivo e disponível para dispositivos móveis.

Aí você pergunta: "Aiinnnnnnnn João, isso deve ser uma nota e eu não tenho como pagar !!"

Não, você está errada. Tudo isso é totalmente de graça e online !!

Vale a pena você dar uma olhada.

Uma coisa que é importante citar é que você pode integrar o Trello com sua conta Google e pronto, é só partir para o abraço e usar.



Leia Mais ››

sexta-feira, 23 de janeiro de 2015

Árvore binária - Implementação em Java

Olá amados leitores. Hoje iremos estudar um tema muito interessante nas estruturas de dados, as árvores binárias. Para você que já conhece toda a parte teórica da coisa e só quer um exemplo prático, você pode clicar aqui e baixar um projeto pronto.

Ahhhhhhhhhhhhhhhhh, antes que alguém me pergunte: "Ainnn João, você vai falar sobre balanceamento ?"

Eu já respondo: "Não vou falar porque senão o post vai ficar extremamente extenso". Você vai ter que correr por fora amigo.

Vamos começar então ?!

Você sabe o que é uma árvore binária ? 

Não !?

Tudo bem amigo, vamos facilitar um pouco mais a pergunta. To pegando pesado !

Você sabe o que é um árvore (não me refiro a planta) ?

Também não !?

Bem, então, senta aí que lá vem história. Pegue seu café e acenda seu cigarro. Uma árvore, não é nada mais nada menos que, um grafo acíclico. Mas aí você me pergunta: O que é um grafo ?

Vamos descer mais um degrau. Segundo à Wikipedia, a teoria dos grafos é um ramo da matemática que estuda as relações entre os objetos de um determinado conjunto. Para representar tais relações, são usados estruturas chamadas grafos, G(V,A) onde, G é um conjunto de vértices e arestas. Os vértices são um conjunto não vazio dos vértices do grafo. As arestas são um conjunto de pares não ordenados de V. Vamos ao exemplo.

Figura 1 - http://upload.wikimedia.org/wikipedia/commons/thumb/2/24/Tree_graph.svg/162px-Tree_graph.svg.png

Acima, temos o grafo G que é composto por V={1,2,3,4,5,6} e A={{1,4},{2,4},{4,3},{4,5},{5,6}}. Depois de toda essa explicação, você deve estar se perguntando: Para que esta porcaria serve ? Quem usa isso ?

Agora você vai ficar surpreso. Pesquise sobre o problema das sete pontes de Königsberg. Não irei falar sobre o problema das pontes aqui porque não é esse o nosso foco.

Lembra que no início do post, eu falei que uma árvore é um grafo acíclico ? Então, um grafo acíclico é aquele que não faz ciclos, ou seja, se no nosso exemplo acima, o vértice 1 estivesse ligado ao vértice 2, o grafo G não seria uma árvore pois, existiria um ciclo, 1 - 2 - 4.

Agora que, já sabemos o que é um grafo e o que é uma árvore. Vamos falar de suas propriedades:
  • O primeiro nó de uma árvore é o nó raiz.
  • Nó folha é todo nó que não possui conexões.
  • Em uma árvore existe 1 e somente 1 caminho que liga um nó ao outro.
  • Dado um determinado vértice, cada "filho" seu é a "raíz" de uma nova "sub-árvore".
  • Grau de um vértice é o número de sub-árvores do vértice.
  • Altura da árvore é o comprimento do caminho mais longo da raiz até uma das suas folhas.
  • O nível de um nó é o número de nós no caminho entre o vértice e a raiz.

Precisamos saber o que é uma árvore binária. Afinal de contas, estamos aqui para isso. As árvores binárias são um tipo de árvore onde, cada um de seus vértices pode possuir no máximo duas sub-árvores. O grau (número de filhos) de cada vértice pode ser 0, 1 ou 2.

Figura 2

Acima, temos um exemplo de árvore binária. Neste momento, não se preocupe em entender como os valores foram gravados ali. Veremos isto adiante. Vamos a melhor parte do post, vamos implementar !!!

Usaremos uma lista encadeada para construir nossa árvore por questões de performance. Se você não sabe o que é uma lista encadeada, eu recomendo que você dê uma olhada nesse post:


Vamos primeiro criar métodos para retornar se a árvore está vazia ou não, a quantidade de nós da árvore, altura da árvore e um método que imprima todos os valores da árvore. A forma que a árvore é percorrida é em pós-ordem pois, dessa forma é garantido que irei percorrer todos os filhos de um nó primeiro e só depois irei acessar o nó pai. Dessa forma, realizo as operações na árvore de um jeito mais seguro.

Crie as seguintes classes:

package pkg;
public class Node {
    private Integer valor;
    private Node noEsquerda;
    private Node noDireita;  
    public Node() { }
  
  public Node(Integer valor) {
        super();
        this.valor = valor;
    }
    public Integer getValor() {
        return valor;
    }
    public void setValor(Integer valor) {
        this.valor = valor;
    }
    public Node getNoEsquerda() {
        return noEsquerda;
    }
    public void setNoEsquerda(Node noEsquerda) {
        this.noEsquerda = noEsquerda;
    }
  public Node getNoDireita() {
        return noDireita;
    }
    public void setNoDireita(Node noDireita) {
        this.noDireita = noDireita;
    }
    @Override
    public String toString() {
        return "Node [valor=" + valor + "]";
    }    
}

package pkg;

public class BinaryTree {
    private Node root;

    public boolean isEmpty(){
        if(root == null){
            return true;
        }
        return false;
    }
    
    public int getAltura(){
        return getAltura(this.root);
    }
    
    private int getAltura(Node root){
        if(root == null){
            return 0;
        }
        int altEsq = getAltura(root.getNoEsquerda());
        int altDir = getAltura(root.getNoDireita());
        if(altEsq > altDir){
            return altEsq + 1;
        } else {
            return altDir + 1;
        }
    }
    
    public int getQtdNode(){
        return getQtdNode(root);
    }
    
    private int getQtdNode(Node root){
        if(root == null){
            return 0;
        }
        int qtdNodeEsq = getQtdNode(root.getNoEsquerda());
        int qtdNodeDireita = getQtdNode(root.getNoDireita());
        return qtdNodeEsq + qtdNodeDireita + 1;
    }
    
    public void imprimirArvore(){
        if(this.root == null)
            System.out.println("Árvore vazia");
        else
            imprimirArvore(this.root);
    }
    
    private void imprimirArvore(Node node){
        if(node.getNoEsquerda() != null){
            imprimirArvore(node.getNoEsquerda());
        }
        if (node.getNoDireita() != null){
            imprimirArvore(node.getNoDireita());
        }
        System.out.println("Nó: " + node.getValor());
    }
    
    public void inserir(int valor){
        inserir(this.root, valor);
    }
    
    public void inserir(Node node, int valor) {
        if(this.root == null){
            this.root = new Node(valor);
        } else {
            if (valor < node.getValor()) {
                if (node.getNoEsquerda() != null) { 
                    inserir(node.getNoEsquerda(), valor); 
                } else { 
                    //Se nodo esquerdo vazio insere o novo no aqui 
                    node.setNoEsquerda(new Node(valor)); 
                } 
                //Verifica se o valor a ser inserido é maior que o no corrente da árvore, se sim vai para subarvore direita 
            } else if (valor > node.getValor()) { 
                //Se tiver elemento no no direito continua a busca 
                if (node.getNoDireita() != null) { 
                    inserir(node.getNoDireita(), valor); 
                } else {
                    //Se nodo direito vazio insere o novo no aqui 
                    node.setNoDireita(new Node(valor)); 
                } 
            }
        }
    }
    
    public Node remover(int valor) throws Exception{
        return remover(this.root, valor);
    }
    
    private Node remover(Node node, int valor) throws Exception{
        if(this.root == null){
            throw new Exception("Árvore vazia");
        } else {            
            if(valor < node.getValor()){
                node.setNoEsquerda(remover(node.getNoEsquerda(), valor));
            } else if(valor > node.getValor()){
                node.setNoDireita(remover(node.getNoDireita(), valor));
            } else if (node.getNoEsquerda() != null && node.getNoDireita() != null) {
                /*2 filhos*/  
                System.out.println("  Removeu No " + node.getValor());
                node.setValor(encontraMinimo(node.getNoDireita()).getValor());
                node.setNoDireita(removeMinimo(node.getNoDireita()));
            } else {  
                System.out.println("  Removeu No " + node.getValor());  
                node = (node.getNoEsquerda() != null) ? node.getNoEsquerda() : node.getNoDireita();  
            }  
            return node;
        }
    }
    
    private Node removeMinimo(Node node) {  
        if (node == null) {  
            System.out.println("  ERRO ");  
        } else if (node.getNoEsquerda() != null) {  
            node.setNoEsquerda(removeMinimo(node.getNoEsquerda()));  
            return node;  
        } else {  
            return node.getNoDireita();  
        }  
        return null;  
    }  
  
    private Node encontraMinimo(Node node) {  
        if (node != null) {  
            while (node.getNoEsquerda() != null) {  
                node = node.getNoEsquerda();  
            }  
        }  
        return node;  
    }
}

Agora que você já criou as classes. Vamos entender os métodos da classe BinaryTree.

Método isEmpty():

Esse método é o mais simples de todos. Para saber se a árvore está vazia ou não, precisamos somente saber se seu root é nulo. Caso ele seja, a árvore estará vazia pois, no root é onde começam as conexões com outros nós.

Método getAltura()getAltura(Node root):

Esses métodos são sobrecarregados pois, o segundo é recursivo. A recursividade do segundo método se dá pelo fato de que, quando estamos trabalhando com árvore e precisamos percorrê-las, temos que chegar até sua folha da esquerda, depois chegar até sua folha da direita e por último analisar a raiz. Sem recursividade isso não seria possível. Para descobrir a altura, precisamos primeiro descobrir a altura do nó da esquerda, depois do nó da direita e somar 1. É necessário somar 1 pois a altura dos nós folha é 0. 

Precisamos comparar se a altura da esquerdá é maior do que a da direita porque, a altura de uma árvore é o maior caminho da raiz até a folha mais longe. Logo, quanto maior a altura do nó mais longe ele está da raiz. Caso você ainda tenha dúvidas para entender essa função, recomendo que você assita esse vídeo: https://www.youtube.com/watch?v=qVnNdmx4fOA

Método getQtdNode()getQtdNode(Node root):

Esses métodos são sobrecarregados pelo mesmo motivo que o método getAltura() é sobrecarregado também. Para descobrir a quantidade de nós da árvore, precisamos descobrir a quantidade de nós a esquerda e à direita e somar 1. Somar 1 significa que estamos levando em conta o nó raiz.

Método imprimirArvore()imprimirArvore(Node node):

Imprime a árvore de forma pós-ordem, ou seja, acessa primeiro nó esquerdo, depois nó direito e por último a raiz. Para cada nó, seu valor é impresso no console.

Tcharammmmmmmm !!! 

Já entendemos quatro métodos da nossa API de árvore binária. Faltam os métodos para inserir e remover. Para realizarmos isso precisamos entender um novo conceito: árvore binária de busca. A árvore binária de busca é um tipo de árvore binária que estabelece que todos os valores à esquerda do nó pai devem ser menores que o mesmo e todos os valores à direita devem ser maiores que o nó pai. Entendeu agora porque eu não quis entrar em detalhes na figura 2 ?

As inserções e remoções devem respeitar essa regra. Caso contrário, a árvore não será mais uma árvore binária de busca.

Falarei de inserção e remoção de valores em árvores binária de busca porque, é o que é mais feito pelos autores em livros. Se quiséssemos estudar a inserção e remoção em árvore binárias comuns, precisaríamos somente saber os conceitos básicos dessa árvore. Dessa forma, você em 1 post aprende dois tipos de árvores.

Método inserir(int valor) e inserir(Node node, int valor):
  1. Começo a percorrer a árvore pela raiz
  2. Avalio se o valor que está sendo inserido é maior ou menor (não pode ser igual) do que o nó que estou avaliando.
  3. Caso seja menor, avalio se já existe um nó na esquerda e repito o passo 2.
  4. Caso não haja um nó esquerdo, crio um e gravo o novo valor ali.
  5. Caso o valor seja maior do que o nó que estou avaliando, avalio se já existe um nó na direita e repito o passo 2.
  6. Caso não haja um nó direito, crio um e gravo o novo valor ali.

Método remover(int valor)remover(Node node, int valor):
  1. Avalio se a raíz é null. Caso seja informo que a árvore está vazia.
  2. Caso a raíz não seja null. Avalio se o valor que quero remover é maior ou menor que o nó que estou avaliando (o primeiro nó é a raíz, obviamente).
  3. Caso seja menor, acesso o nó esquerdo e faço isso até encontrá-lo.
  4. Quando encontro ele, avalio se ele tem filhos à esquerda e à direita.
  5. Caso tenha, vou para a sub-árvore da direita e procuro o nó de menor valor à esquerda. Depois de encontrá-lo, atribuo o valor desse menor nó ao nó que está sendo excluído (ver imagem 5).
  6. Depois da atribuição do passo 5 ter sido feita, eu preciso refazer a ligação que o pai do menor nó à esquerda tinha pois, agora o pai dele vai apontar para null.
  7. O valor passado como parâmetro foi excluído.
  8. Ao contrário do passo 3, ou seja, o valor é maior, acesso o nó direito e faço isso até encontrá-lo.
  9. Repito os passos 4 à 7.
  10. Caso um nó seja folha ou só tenha 1 filho, removo seu valor e atualizo seu pai.
Para ficar mais fácil, olhe as imagens 3, 4 e 5.

Figura 3 - Excluindo nó folha - http://upload.wikimedia.org/wikipedia/commons/6/6c/Bstreedeleteleafexample.jpg

Figura 4 - Excluindo nó com 1 filho - http://upload.wikimedia.org/wikipedia/commons/6/6a/Bstreedeleteonechildexample.jpg

Figura 5 - Excluindo um nó com dois filhos - http://upload.wikimedia.org/wikipedia/commons/1/15/Bstreedeletenotrightchildexample.jpg


Bem amigos, esse post ficou grande mas, espero que esteja tudo bem explicado.

Terminamos !! Ufa !! 

Sugestões ?! Críticas ?! Elogios ?! 

Deixe aí nos comentários ou na nossa página do facebook.



Referências:
[ED] Aula 69 - Árvore Binária: Definição - https://www.youtube.com/watch?v=9WxCeWX9qDs
[ED] Aula 70 - Árvore Binária: Implementação - https://www.youtube.com/watch?v=TR8ZLUKmcPc
[ED] Aula 72 - Árvore Binária: informações básicas - https://www.youtube.com/watch?v=qVnNdmx4fOA
[ED] Aula 73 - Percorrendo uma Árvore Binária - https://www.youtube.com/watch?v=z7XwVVYQRAA
[ED] Aula 74 - Árvore Binária de Busca - https://www.youtube.com/watch?v=M7cb4HjePJk
[ED] Aula 75 - Inserção em Árvore Binária de Busca - https://www.youtube.com/watch?v=8cdbmsPaR-k
[ED] Aula 76 - Remoção em Árvore Binária de Busca - https://www.youtube.com/watch?v=_0Yu9BSYXGY
http://javafree.uol.com.br/topic-882029-Arvore-binaria.html
Leia Mais ››

segunda-feira, 29 de dezembro de 2014

Regex para validação de moeda

Olá amigos leitores. O tema do post dessa semana foi escolhido por uma necessidade que tive muito tempo atrás. Quando me deparei com o problema aplicar máscaras monetárias (R$) em campos de texto, resolvi construir uma solução própria. Poderia ter usado soluções prontas ? Sim, poderia mas, eu não queria ficar amarrado à soluções de terceiros.

Para resolver o problema, não queria criar uma função grande e de complexidade elevada sendo que, uma regex poderia lidar com esse problema. Então, vamos lá !!

A regex construída:

 ^R\$(\d{1,3}(\.\d{3})*|\d+)(\,\d{2})?$  

Esta regex aceita estes valores:
  • R$2,00
  • R$20,00
  • R$2.000,00
  • R$20.000,00
  • R$200.000,00
  • R$2.000.000,00
Mas, não aceita esses:
  • 2,00
  • 2
  • R$aaa44,00
  • B$20,00
  • $100,00
Importante: Note que o caracter usado para separar os reais dos centavos é o vírgula (,) e não o ponto (.).

Agora, vamos às partes das explicações. Vamos destrinchar a regex.

Os caracteres ^ e $, respectivamente, no início e fim da expressão regular denotam um intervalo fechado, ou seja, o texto que for avaliado só pode conter o dado monetário.

O caracter representa o próprio R do R$. Então, até aí, nenhum mistério. O $ possui significado especial nas regex, logo precisamos de uma barra de escape (\$) para que ela adote a representação de cifrão ($).

Com (\d{1,3}(\.\d{3})*|\d+) definimos que teremos ou algo desse tipo: 2.000 ou 2000. Vamos melhorar isso.

\d{1,3} -> \d representa um dígito. O {1,3} representa no mínimo 1 e no máximo 3 ocorrências. Então, quando temos \d{1,3} estamos querendo dizer que, teremos um dígito que terá no mínimo 1 e no máximo 3 ocorrências.
(....) -> Os parênteses () são usados para definir um subconjunto.
\. -> A barra de escape é usada no ponto (.) para definir o separador de milhar.
\d{3} -> Representa um dígito que será repetido três vezes.
* -> Representa que algo será repetido 0 ou infinitas vezes.
| -> Representa uma operação de ou.
\d+ -> Representa que um dígito será repetido no mínimo 1 e no máximo infinitas vezes.

Agora, que já deciframos uma parte da regex, falta a outra parte: (\,\d{2})?
Essa parte define os centavos logo, algo assim será aceito: ,00.

\, -> Caracter vírgula (,) com barra de escape para assumir a representação de vírgula.
\d{2} -> Ver explicação acima.
(....) -> Ver explicação acima.
? -> Representa que algo será repetido 0 ou 1 vez.

Agora que já esmiuçamos toda a regex, já entendemos como ela funciona e como ela aceita os valores descritos acima. É só pegar e usar.

Sugestões ? Críticas ? Elogios ? Deixe aí embaixo nos comentários ou, na página do facebook.

Página do facebook: https://www.facebook.com/precisoestudarsempre/
Leia Mais ››

terça-feira, 23 de dezembro de 2014

Listas encadeadas em Java

Olá caros leitores do blog Preciso Estudar Sempre, o tópico desta semana será sobre listas encadeadas. Escolhi esse tema porque acredito que é importante e porque não me lembro de ter falado sobre tal antes.

O conhecimento deste assunto é de grande importância no desenvolvimento de software pois, as listas encadeadas possuem uma estrutura bem diferente das listas tradicionais. Tal estrutura que pode nos ajudar em certas situações.

Antes que você se impressione com o assunto, eu já digo: "Fique tranquilo". Este tema é de fácil entendimento. Porém, é necessário de um pouco de conhecimento de programação.

Para os que já conhecem o assunto ou que já ouviram falar, já aviso que não falarei sobre listas duplamente encadeadas ou listas circulares porque senão o post ficará muito extenso e massante.

No Java, já existem estruturas prontas para listas encadeadas. Estou falando da LinkedList, clique aqui para ver a documentação. Mas, nesse post iremos criar nossa própria estrutura de lista encadeada.

Para realizar este estudo não é necessário ter uma IDE super moderna. Se você quiser usar o notepad não tem problema.

Primeiro, vamos entender o conceito das listas encadeadas. As listas tradicionais tem suas células organizadas todas juntas e posicionadas uma atrás da outra. Isso lhes garante velocidade em buscas e acesso randômico, ou seja, eu posso acessar qualquer posição que eu queira. Porém, existe uma desvantagem nesta estrutura. Quando eu preciso inserir ou remover elementos no meio da lista, o trabalho para reconstruir a lista com todos elementos é muito grande visto que, eu preciso remover os elementos que virão após o novo/removido elemento e depois recolocá-los, formando assim uma lista maior/menor.

http://voidexception.weebly.com/uploads/1/1/9/4/11944659/4652147_orig.jpg

Com as listas encadeadas não existe este problema porque suas células são organizadas de forma diferente. Nas listas tradicionais, cada elemento não tem conhecimento do próximo elemento ou do anterior porque estão todas juntas dentro da estrutura. Nas lista encadeadas, não. Cada elemento está "solto" na memória. Então, agora, você fica com aquela dúvida.

"Se os elementos estão soltos, como a lista é montada ? "

A resposta é simples, cada elemento possui uma referência somente para o próximo elemento. Como se formassem uma corrente, como se estivessem ligados (daí que vem o nome Linked List). Na figura abaixo, temos um exemplo perfeito de como é essa lista.

http://www.ime.usp.br/~pf/algoritmos/xfig/lista2a.gif

Os elos da lista são formados por ponteiros que possuem a referência para o próximo elemento. Quando não existe a referência para o próximo elemento, o ponteiro assume o valor nulo. Abaixo, temos uma relação de vantagens e desvantagens dessa estrutura.

Vantagens:
  • Linked lists são estruturas de dados dinâmicos que alocam a memória necessária enquanto o programa está funcionando.
  • Operações de inserir e deletar células (nodes) são facilmente implementadas.
  • Estruturas de dados lineares tais como, pilhas e filas são facilmente executadas com uma lista encadeada.
  • Eles podem reduzir o tempo de acesso e podem aumentar em tempo real sem overhead de memória.
Desvantagens:
  • Tem tendência de desperdiçar memória pelo fato dos ponteiros pediram novo espaço de armazenamento.
  • Nós em uma lista encadeada devem ser lidos do início.
  • Dificuldades surgem em listas encadeadas quando se tente percorrê-la de trás para frente. Tal tarefa é extremamente complicado. Adicionar um backpointer (ponteiro de ré) causa desperdício de memória.
Agora que já sabemos como a lista encadeada funciona, vamos ao exemplo prático. Nós criaremos uma lista encadeada que representa uma escala de indicação de empregos, ou seja, uma pessoa indica a outra para uma vaga de emprego mas, ela só pode indicar 1 pessoa e só conhece a pessoa que indicou.

Crie a classe Pessoa. Esta classe representa a pessoa.

 package pkg;  

 public class Pessoa { 
      private Integer id; 
      private String nome; 
      private String email; 
      public Pessoa() { 

      } 

      public Pessoa(Integer id, String nome, String email) { 
           this.id = id; 
           this.nome = nome; 
           this.email = email; 
      } 

      public Integer getId() { 
           return id; 
      } 

      public void setId(Integer id) { 
           this.id = id; 
      } 

      public String getNome() { 
           return nome; 
      } 

      public void setNome(String nome) { 
           this.nome = nome; 
      } 

      public String getEmail() { 
           return email; 
      } 

      public void setEmail(String email) { 
           this.email = email; 
      } 

      @Override 
      public String toString() { 
           return "Pessoa [id=" + id + ", nome=" + nome + ", email=" + email + "]"; 
      } 
 } 

Crie a classe Celula. Esta classe representa a célula (posição ou node) da lista. Como vimos acima, cada célula precisa da referência do próximo e isso é feito através do atributo proximo.

 package pkg;  

 public class Celula { 
      private Celula proximo; 
      private Pessoa valor; 
      public Celula getProximo() { 
           return proximo; 
      } 

      public void setProximo(Celula proximo) { 
           this.proximo = proximo; 
      } 

      public Pessoa getValor() { 
           return valor; 
      } 

      public void setValor(Pessoa valor) { 
           this.valor = valor; 
      } 
 } 

Crie a classe ListaEncadeada. Esta classe representa a lista encadeada. Note que ela não guarda suas células em nenhum tipo de array ou vetor. As únicas referências que ela tem para suas células são os atributos primeiro e ultimo. A partir deste dois atributos, será realizada as operações na lista. O atributo posicaoAtual é usado para as operações iteração e recuperação do objeto do laço.

 package pkg;  
 public class ListaEncadeada { 
      private Celula primeiro; 
      private Celula ultimo; 
      private Celula posicaoAtual; 
      /** 
       * Adiciona uma pessoa no fim da lista. 
       * @param valor 
       */ 
      public void adicionar(Pessoa valor){ 
           Celula celula = new Celula(); 
           celula.setValor(valor); 
           if(primeiro == null && ultimo == null){ 
                primeiro = celula; 
                ultimo = celula; 
           } else { 
                ultimo.setProximo(celula); 
                ultimo = celula; 
           } 
      } 
      /** 
       * Remove uma pessoa do fim da lista. 
       */ 
      public void remover(){ 
           if(primeiro.getProximo() != null){ 
                Celula celula = this.recuperarPenultimo(this.primeiro); 
                ultimo = celula; 
                celula.setProximo(null); 
           } else { 
                primeiro = ultimo = null; 
           } 
      } 
      /** 
       * Recupera o penultimo elemento da lista 
       * @param celula 
       * @return 
       */ 
      private Celula recuperarPenultimo(Celula celula){ 
           if(celula.getProximo().equals(ultimo)){ 
                return celula; 
           } 
           return recuperarPenultimo(celula.getProximo()); 
      } 
      public boolean temProximo(){ 
           if(primeiro == null){ 
                return false; 
           } else if (posicaoAtual == null){ 
                posicaoAtual = primeiro; 
                return true; 
           } else { 
                boolean temProximo = posicaoAtual.getProximo() != null ? true : false; 
                posicaoAtual = posicaoAtual.getProximo(); 
                return temProximo; 
           } 
      } 
      public Celula getPosicaoAtual(){ 
           return this.posicaoAtual; 
      } 
 } 

Agora, crie a classe Principal. Esta classe contém o método main e a partir dele, chamamos os método da lista.

 package pkg;  
 public class Principal { 
      public static void main(String[] args) { 
           ListaEncadeada listaEncadeada = new ListaEncadeada(); 
           Principal principal = new Principal(); 
           principal.adicionarPessoa(listaEncadeada); 
           principal.remover(listaEncadeada); 
           while(listaEncadeada.temProximo()){ 
                System.out.println(listaEncadeada.getPosicaoAtual().getValor()); 
           } 
      } 
      private void adicionarPessoa(ListaEncadeada listaEncadeada){ 
           Pessoa p1 = new Pessoa(1, "João", "jp@gmail.com"); 
           Pessoa p2 = new Pessoa(2, "Maria", "maria@gmail.com"); 
           Pessoa p3 = new Pessoa(3, "Bruno", "bruno@gmail.com"); 
           Pessoa p4 = new Pessoa(4, "José", "jose@gmail.com"); 
           Pessoa p5 = new Pessoa(5, "Mário", "mario@gmail.com"); 
           Pessoa p6 = new Pessoa(6, "Eduardo", "dudu@gmail.com"); 
           listaEncadeada.adicionar(p1); 
           listaEncadeada.adicionar(p2); 
           listaEncadeada.adicionar(p3); 
           listaEncadeada.adicionar(p4); 
           listaEncadeada.adicionar(p5); 
           listaEncadeada.adicionar(p6); 
      } 
      private void remover(ListaEncadeada listaEncadeada){ 
           listaEncadeada.remover(); 
           listaEncadeada.remover(); 
           listaEncadeada.remover(); 
      } 
 } 

Não entrei muito a fundo nas operações que são possíveis realizar em uma lista encadeada porque, eu ficaria um mês todo escrevendo este post e no fim disponibilizaria uma API muito extensa. O meu intuito com esse post é apenas dar um guia introdutório do assunto visando, dar insumos suficientes para que os leitores possa andar "pelas suas próprias pernas".

Para baixar o projeto completo, clique aqui.

Sugestões ? Críticas ? Elogios ? Deixe aí nos comentários ou na página do facebook.

https://www.facebook.com/precisoestudarsempre/

Referências:
http://www.ime.usp.br/~pf/algoritmos/aulas/lista.html
http://en.wikipedia.org/wiki/Linked_list
http://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html
Leia Mais ››

quarta-feira, 17 de dezembro de 2014

Entendendo o SMTP

Eu sempre tive bastante dúvida sobre esse assunto. Como funcionam os protocolos de email ? Como a troca de mensagens é realizada ? Na faculdade, esse tema é abordado mas, de uma forma muito superficial logo, isso não me deixou satisfeito.

Então, o post dessa semana será: "Entendendo o SMTP".

Acredito que a melhor fonte de pesquisa para este assunto seja sua RFC (Request for Comment), a RFC 5321.

De acordo com a RFC, para realizar uma transferência de mensagem para um servidor SMTP, um SMTP client estabelece uma canal de transmissão de duas vias para um servidor. Um SMTP client determina o endereço de um determinado servidor SMTP pela resolução de um domínio de destino para um servidor de Mail eXchanger ou um servidor final.

Um servidor SMTP pode ser ou o destino final ou um destino intermediário (pode assumir o papel de um SMTP client após receber a mensagem) ou um gateway (pode transportar a mensagem à frente usando algum protocolo diferente do SMTP). Os comandos SMTP são gerados pelo SMTP Client e enviados ao servidor SMTP. Respostas SMTP são enviadas do servidor para o cliente em resposta aos comandos.


Em outras palavras, transferência de mensagens podem ocorrer em uma única conexão entre o original SMTP-remetente e o final SMTP-destinário, ou podem ocorrer em uma série de pulos através de sistemas intermediários. Em outros casos, uma vez que o servidor publicou uma resposta de sucesso no fim do dado da mensagem, uma transferência de responsabilidade pela mensagem ocorre: o protocolo requer que o servidor deve aceitar a responsabilidade de também entregar mensagem ou reportar apropriadamente a falha da entrega, caso ocorra (veja seções 6.1, 6.2 e 7.8 da RFC).

Uma vez que o canal de transmissão foi estabelecido e o inicial handshaking é feito, o SMTP Client, normalmente, inicia uma transação de mensagem. Tal transação consiste em um série de comandos para especificar o remetente e destinatário da mensagem e transmissão do conteúdo da mesma (incluindo qualquer linha na seção de cabeçalho ou outra estrutura). Quando a mesma mensagem é enviada para vários recipientes, este protocolo encoraja a transmissão de uma única cópia dos dados para todos os recipientes do mesmo servidor de destino (ou servidor retransmissor intermediário).

O servidor responde com uma resposta para cada comando. Respostas podem indicar que o comando foi aceito, que comandos adicionais são esperados, ou que um condição de erro temporário ou permanente existe. Comandos que especifiquem o remetente ou recipientes pode incluir requisições de extensão de serviço SMTP server-permitted (ver seção 2.2 da RFC). O diálogo é propositalmente lock-step (trava e faço), one-at-a-time (um de cada vez), embora isso possa ser modificado por um acordo mútuo a partir de requisições de extensão tais como comandos de pipelining.

Uma vez que dada mensagem foi transmitida, o client pode ou pedir que a conexão seja encerrada ou iniciar outra transação. Mais adiante, um SMTP Client pode usar uma conexão para um servidor SMTP para serviços auxiliares tais como verificação de endereços de email ou recuperação de endereços dos participantes da mailing list.

Como dito acima, este protocolo provê mecanismos para a transmissão de mensagens. Historicamente, esta transmissão normalmente ocorria diretamente do servidor remetente para o servidor destinatário quando os dois estavam conectados ao mesmo serviço de transporte. Quando eles não estão conectados ao mesmo serviço de transporte, a transmissão ocorre via um ou mais servidor de retransmissão SMTP. Um caso muito comum na internet, atualmente, envolve submissão da mensagem original para um intermediário, servidor de submissão de mensagem, o qual é similar a uma retransmissão mas possui algumas propriedades adicionais. Um servidor intermediário que atue como ou um retransmissor SMTP ou como um gateway em alguns ambientes de transmissão é geralmente selecionado através do uso do mecanismo Mail eXchanger DNS.

É isso galera, espero ter trazido este conteúdo da RFC de forma bem clara e explicativa.

Dúvidas, sugestões ou críticas ? Deixe aí embaixo nos comentários ou pelo facebook do Preciso Estudar Sempre.

https://www.facebook.com/precisoestudarsempre/
   

Referência: http://tools.ietf.org/html/rfc5321#page-7
Leia Mais ››

quinta-feira, 4 de dezembro de 2014

Entendendo o SSL

Este assunto sempre me deixou bastante intrigado pois, eu sempre me perguntava o que era aquele https, na barra de endereço do meu browser. Então, decidi criar esse post para que, as pessoas possam ter um entendimento maior sobre esse assunto.

Hoje, nossa "aulinha" será mais teórica. Então, você que está ávido por alguma classe Java ou algum SQL, se acalme por favor. É importante citar que, para que você possa entender o assunto abordado, é de extrema necessidade que você entenda a arquitetura cliente-servidor.

Caso não conheça, clique aqui e leia sobre o assunto.

Na minha incansável procura pelo significado do https, notei que sera sempre levado pelas minhas fontes para textos que abordavam o protocolo de segurança SSL. Então, concluí que, eu precisava primeiro aprender mais sobre o protocolo para assim, entender consequentemente o que significa o tal https.

O SSL, abreviação para Secured Socket Layer, é um protocolo de segurança, conforme dito acima, que permite que aplicativos cliente/servidor possam trocar informações em total segurança, protegendo a integridade e a veracidade do conteúdo que trafega na Internet. Tal segurança só é possível através da autenticação das partes envolvidas na troca de informações.

Seu funcionamento é bastante simples. Quando você abre seu browser, digita algum site na barra de endereço e aperta Enter, uma requisição de acesso é realizada. Essa requisição verifica se existe algum certificado digital. Caso exista, é solicitado o envio deste certificado (tome como idéia este certificado como se fosse um documento de identidade). Após recebido é verificado se o certificado é confiável, válido e se está relacionado com o site que o enviou.

Caso o certificado seja confiável, uma chave pública é enviada pelo browser para o servidor. No momento que esta chave é recebida, o servidor compara a chave pública com sua chave particular. Caso sejam compatíveis, uma comunicação segura é iniciada. Uma mensagem que tenha sido criptografada com uma chave pública somente poderá ser decifrada com a sua chave privada (simétrica) correspondente.

A imagem abaixo foi retirada deste link e exemplifica bem o que estou dizendo. Com ela é possível um total entendimento de como o SSL funciona entre o browser e o servidor.


Agora sabemos o que se trata o nosso https, ele é nada mais, nada menos que uma requisição http segura onde, o s significa secured.

Espero ter ajudado e esclarecido este conceito na mente de vocês.

Sugestões ? Críticas ? Melhorias ? Deixe aí embaixo nos comentários ou comente também na página do facebook.

Preciso Estudar Sempre: https://www.facebook.com/precisoestudarsempre/

Referências:
http://www.techtudo.com.br/artigos/noticia/2012/01/o-que-e-ssl.html
http://www.tecmundo.com.br/seguranca/1896-o-que-e-ssl-.htm
http://www.webopedia.com/TERM/S/SSL.html
Leia Mais ››