Tabela de espalhamento
A tabela de espalhamento ou tabela de hash é uma estrutura que consiste em indexar os elementos armazenados de maneira que seja fácil e rápido encontrar qualquer elemento a partir de sua chave.
Essa estrutura não tem a premissa de armazenar os elementos de maneira sequencial e sim de identificar uma categoria para o elemento e armazená-lo de acordo.
É uma estrutura muito usada tanto na computação quanto no dia a dia.
- Agenda telefônica
- Corredores de supermercado
- Organizar livros em uma biblioteca
O primeiro passo é identificar a qual categoria pertence o elemento que queremos armazenar, para isso temos a "função hash". Esta função é responsável por gerar o índice do elemento. Portanto, essa função deve ser escolhida com cuidado pois caso a função seja mal implementada a tabela terá uma performance ruim.
Vamos pegar um exemplo de uma agenda telefônica.
Para armazenar o nome "Geraldo", executamos a função hash que irá produzir o índice "G".
Já o nome "Nayara" irá produzir o índice "N" e o nome "Fábio" irá produzir o índice "F".
Desta maneira sabemos que os elementos serão armazenados da seguinte maneira:
Para recuperar o nome "Fábio" usamos novamente o índice "F" e acessamos o elemento diretamente.
Mesmo que a nossa "função hash" seja muito boa, ainda assim estamos sujeitos a colisões, que é quando dois elementos distintos produzem o mesmo índice. O nome "Francisco" também produz o índice "F" e no exemplo acima ocorreria uma colisão com o nome "Fábio".
Nesse caso precisamos combinar mais de uma estrutura para permitir que os dois elementos possam coexistir.
Podemos combinar as estruturas "tabela de espalhamento" e alguma outra estrutura que melhor encaixe no nosso contexto como Pilhas, Filas e Listas, etc.
public class TabelaEspalhamentoApp { public static void main(String[] args) { TabelaEspalhamento tabela = new TabelaEspalhamento(); tabela.adiciona("Nayara"); tabela.adiciona("Geraldo"); tabela.adiciona("Gorge"); tabela.adiciona("Fabio"); System.out.println(tabela.contem("Geraldo")); tabela.remove("Gorge"); System.out.println(tabela.contem("Geraldo")); System.out.println(tabela.contem("Gorge")); } }
public class TabelaEspalhamento { VetorGenerico vetor = new VetorGenerico(); public void remove(String elemento) { int indice = recuperarIndice(elemento); Vetor v = (Vetor) vetor.get(indice); if (v != null) { int posicao = v.indice(elemento); if (posicao >= 0) { v.remove(posicao); } } } public boolean contem(String elemento) { int indice = recuperarIndice(elemento); Vetor v = (Vetor) vetor.get(indice); if (v != null) { return v.has(elemento); } return false; } public void adiciona(String elemento) { int indice = recuperarIndice(elemento); Vetor v = (Vetor) vetor.get(indice); if (v == null) { v = new Vetor(); } v.add(elemento); vetor.add(indice, v); } private int recuperarIndice(String elemento) { return elemento.charAt(0) % 75; } }
public class VetorGenerico{ Object[] elementos = new Object[1000]; int indice; public void add(Object elemento) { elementos[indice] = elemento; indice++; } public Object get(int i) { return elementos[i]; } public void add(int posicao, Object elemento) { for (int i = indice - 1; i >= posicao; i--) { elementos[i + 1] = elementos[i]; } elementos[posicao] = elemento; indice++; } public void remove(int posicao) { elementos[posicao] = null; for (int i = posicao; i + 1 < elementos.length; i++) { elementos[i] = elementos[i + 1]; } indice--; } }