Escolar Documentos
Profissional Documentos
Cultura Documentos
Tabelas de Hash
As tabelas de hash são muito eficientes
nas operações de pesquisa
As inserções são também muito rápidas
Não permitem a ordenação de dados
1
Tabelas de Hash – Endereçamento directo
Nestas tabelas o vector tem tantas
posições como o número de elementos a
guardar
Cada elemento tem assim uma posição
pré-determinada em função da sua
chave
Elementos possíveis * 0 Tabela de hash de
1 Acesso directo
1 1
* 2
0 6 3 3
2 * 4
5 * 5
3
4 6 6
8 * 7
7
8 8
2
Tabelas de Hash – Endereçamento directo
Classe para representar uma tabela de
hash com endereçamento directo
Como se vai ver, nestes casos, não é
necessário guardar a chave junto com o
elemento
Para simplificar vai-se usar chaves
inteiras
class TabelaHash {
3
Tabelas de Hash – Endereçamento directo
Inserir na tabela
É necessário indicar o elemento e a
chave
A inserção é directa!
4
Tabelas de Hash – Endereçamento directo
Eliminar da tabela
É necessário indicar a chave a eliminar
A eliminação é directa!
void limpar( ) {
5
Tabelas de Hash
Mas, e se o número de elementos a
colocar na tabela for maior que o
número de elementos da tabela?
Tem-se de usar uma conversão da
chave para a posição da tabela
É a esta conversão que se chama
hashing
A escolha de uma boa função de
hashing é fundamental
Tabelas de Hash
Para o exemplo seguinte vai-se usar a
função
Hash1( x ) = x % 13
Elementos possíveis Tabela de hash
0 13 Hash1( 13 ) = 0
1 1 Hash1( 1 ) = 1
2 Hash1( 28 ) = 2
54 2 28
20 50 1 3 3 Hash1( 3 ) = 3
17 3 * 4
31
6 * 5
0 22
32 8 6 6 Hash1( 6 ) = 6
43 * 7
5 13
8 8 Hash1( 8 ) = 8
4 28
* 9
7 23
* 10
* 11
* 12
Algoritmos e Estruturas de Dados F. Sérgio Barbosa
6
Tabelas de Hash
Para o exemplo seguinte vai-se usar a
função
Hash2( str ) = str.length() % 7
Elementos possíveis Tabela de hash
0 Métodos
e * 1
de 2 Ambientes
Micro 3 Computação
Desenho
Métodos 4 Programação
Gráfica
Computação 5 Micro
Análise
Ambientes * 6
Matemática Programação Hash2( “Micro” ) = 5
Hash2( “Métodos” ) = 0
Disciplina
Hash2( “Computação” ) = 3
Hash2( “Ambientes” ) = 2
Hash2( “Programação” ) = 4
Algoritmos e Estruturas de Dados F. Sérgio Barbosa
Tabelas de Hash
E o que acontece se dois elementos
ficarem na mesma posição?
Dá-se uma colisão!
Como se resolve?
Primeiro vamos tecer algumas
considerações sobre funções de hashing
7
Tabelas de Hash
As funções de hashing:
Devem ser rápidas
Devem evitar ao máximo as colisões:
Cada posição da tabela deve ter a mesma
probabilidade de ser escolhida
A escolha de uma dada função de
hashing não é pois uma decisão directa
Tabelas de Hash
As funções de hashing numéricas:
São muito utilizadas funções do género
de Hash1
Hash( x ) = x % valor
8
Tabelas de Hash
As funções de hashing não numéricas:
Faz-se a conversão para um valor
numérico (exemplo de hash2) e depois
aplicam-se as funções numéricas.
A função que faz a conversão terá de
produzir valores que sejam o mais
diferentes possíveis de modo a
resultarem menos colisões
A função hash2 não é muito razoável,
para dicionários por exemplo.
como a tabela é pequena é muito provável
que muitas strings fiquem na mesma
posição
Algoritmos e Estruturas de Dados F. Sérgio Barbosa
Tabelas de Hash
As funções de hashing não numéricas:
Para strings pode-se também processar alguns (ou
todos) os caracteres de modo a produzir um valor
9
Tabelas de Hash
Voltando ao problemas das colisões
Como se resolve?
Uma solução seria, em cada posição do
vector, colocar uma lista ligada de
elementos
Inserções à cabeça
Cada novo elemento é adicionado à cabeça
dessa lista
Inserções ordenadas
Cada novo elemento é adicionado na
posição correcta da lista
O critério de ordenação será a chave
10
Tabelas de Hash – inserção ordenada
Para o exemplo seguinte vai-se usar a
função
Hash1( x ) = x % 13
Elementos possíveis Tabela de hash
* 0
1 1 14 *
2
54 * 2
20 50 1 3 3 *
17 3 * 4
31
6 * 5
0 22
8 6 6 19 *
32
43 * 7
5 14
8 8 *
4 19
* 9
7 23
* 10
* 11
* 12
Algoritmos e Estruturas de Dados F. Sérgio Barbosa
Tabelas de Hash
Inserção ordenada vs Inserção à cabeça
A inserção à cabeça é mais rápida
Não é preciso percorrer a lista para saber onde
colocar o elemento
Mas não garante que o elemento já lá esteja
Nesse caso seria melhor inserção na cauda
A inserção ordenada pode detectar se
elemento já existe
Como percorre a lista pode detectar se já lá está,
sem perda de processamento
A procura com inserção ordenada é mais
rápida
Já que não é preciso percorrer a lista toda para
determinar se o elemento lá está ou não
A inserção ordenada nem sempre é possível
11
Tabelas de Hash
Estrutura para representar uma tabela
de hash com listas
Nestes caso são necessárias duas
estruturas:
uma para a lista
outra para a tabela
Para efeitos de exemplo vai-se elaborar
uma tabela de automóveis
A chave vai ser a Matrícula
Tabelas de Hash
Classes para representar uma tabela de
hash com listas
class TabelaAuto {
class ListaAuto {
private class No {
String chave; // matricula
Automovel oAuto;
No prox;
}
12
Tabelas de Hash
Criar uma tabela de hash
É necessário indicar o número de
posições
class TabelaAuto {
Tabelas de Hash
Inserir na tabela
É necessário indicar o elemento e a chave
A inserção demora um tempo constante se
for à cabeça
Se for ordenada varia de acordo com a
ocupação da lista
public boolean inserir( String chave, Automovel oAuto ) {
13
Tabelas de Hash
Função de hash
É necessário criar uma função para fazer
o hashing da matricula
Seria necessário testar várias funções
para ver qual daria os melhores
resultados
private int hashAuto( String chave ) {
long resultado = 0;
Tabelas de Hash
Procurar na tabela
É necessário indicar a chave a procurar
A procura demora o tempo de procura
numa lista
Melhores resultados se for inserção
ordenada
14
Tabelas de Hash
Eliminar da tabela
É necessário indicar a chave a eliminar
A eliminação demora o tempo de
eliminação de uma lista
Melhores resultados se for inserção
ordenada (por causa da pesquisa do
elemento)
Tabelas de Hash
Limpar a tabela
15
Tabelas de Hash
Usar a tabela
Tabelas de Hash
Usar a tabela
int lerFicheiro( String nomefich, TabelaAuto carros ) {
// abertura do ficheiro …
while( temInput ) {
// ler dados do carro
Automovel carro = new Automovel();
carro.setMatricula( … );
carro.setProprietario( … );
return nAutos;
}
16
Tabelas de Hash
Usar a tabela
void fazerPesquisas( TabelaAuto carros ) {
String matricula;
Automovel carro;
Tabelas de Hash
E se se pretender uma tabela para
pesquisar, mas desta vez usando o
proprietário como chave?
É preciso fazer outra tabela?
Não, e essa é uma das vantagens de
usar chaves
Desde que seja do mesmo tipo a mesma
tabela dá
Assume-se que não existem dois
proprietários com o mesmo nome! Ou
que o mesmo proprietário tenha dois
automóveis!
Algoritmos e Estruturas de Dados F. Sérgio Barbosa
17
Tabelas de Hash
Usar a tabela
int lerFicheiro( String nomefich, TabelaAuto carros ) {
int nAutos=0;
while( temInput ) {
nAutos++;
}
return nAutos;
}
Tabelas de Hash
Usar a tabela
void fazerPesquisas( TabelaAuto carros ) {
String propri;
Automovel carro;
18
Tabelas de Hash – Endereçamento livre
Neste caso os elementos são colocados
directamente na tabela (como no
endereçamento directo)
No entanto, se a posição estiver ocupada, é
calculada uma nova posição até se encontrar
uma posição livre
Técnica usada quando o número de elementos
possíveis é elevado, mas apenas uma parte
desses elementos é realmente usada
Exemplo: nomes de variáveis (existem infinitas
combinações de nomes, mas num programa são
usados apenas alguns)
19
Tabelas de Hash – Endereçamento livre
Nos três casos recorre-se a uma função,
que além da chave, depende também do
número de tentativas de colocação para
determinar a nova posição de colocação
Todos os casos apresentam uma função
hashEnderecoLivre( chave, tentativa )
O que varia em cada caso é a função –
ou seja, o modo como se usa o número
de tentativas para calcular a nova
posição
}
Algoritmos e Estruturas de Dados F. Sérgio Barbosa
20
Tabelas de Hash – Endereçamento livre
Os construtores podiam ser assim:
class TabelaLivre {
}
Algoritmos e Estruturas de Dados F. Sérgio Barbosa
21
Tabelas de Hash – Endereçamento livre
Sondagem linear:
Quando uma posição está ocupada
tenta-se a seguinte, e assim por diante
até se encontrar uma posição livre
A nova função de hash é assim:
hashLinear( x, i ) = (hash( x ) + i ) % m
Tabelas de Hash
Sondagem linear - exemplo:
Hash( x ) = x % 13
Tabela de hash
* 0 Hash( 1 ) = 1 * 0 Hash( 14 ) = 1
1 1 1 1 Tentativa = 0
* 2 2 14 Posição = 1
1
1 3 3 3 3 Tentativa = 1
3
3 * 4 Hash( 3 ) = 3 * 4 Posição = 2
14
14 * 5 * 5
27
27 * 6 * 6
* 7 2 * 7
2
* 8 * 8
* 9 * 9
* 10 * 10
* 11 * 11
* 12 * 12
0
Algoritmos e Estruturas de Dados /
F. Sérgio Barbosa
22
Tabelas de Hash
Sondagem linear - exemplo:
Hash( x ) = x % 13
Tabela de hash * 0 Hash( 2 ) = 2
* 0 Hash( 27 ) = 1 1 1
Tentativa = 0
1 1 2 14
Tentativa = 0 Posição = 2
2 14 1 3 3
Posição = 1
1 3 3 3 4 27
Tentativa = 1
3 4 27 Tentativa = 1 14 5 2
Posição = 3
14 * 5 Posição = 2 27 * 6
27 * 6 * 7 Tentativa = 2
Tentativa = 2 2
* 7 * 8 Posição = 4
2 Posição = 3
* 8 * 9
* 9 * 10 Tentativa = 3
Tentativa = 3 Posição = 5
* 10 * 11
Posição = 4
* 11 * 12
* 12
Algoritmos e Estruturas de Dados F. Sérgio Barbosa
23
Tabelas de Hash – Endereçamento livre
Sondagem linear - inserção:
Em alternativa podia-se usar a seguinte
função, menos versátil, mas mais
optimizada para a sondagem linear
boolean inserir( int chave, Object oElem ) {
ParChaveElemento par = new ParChaveElemento( chave, oElem );
int key = hash( chave );
key++;
if( key == aTabela.length )
key = 0;
}
return false; // tabela cheia
Algoritmos} e Estruturas de Dados F. Sérgio Barbosa
HashQuadratica( x, i ) = (Hash( x ) + a * i + b * i2 ) % m
24
Tabelas de Hash – Endereçamento livre
Sondagem Quadrática - inserção:
A função de inserir na tabela é igual:
A função HashEnderecoLivre é
substituída pela:
int hashSondagemQuad( int chave, int tentativa) {
25
Tabelas de Hash
Duplo hash - exemplo:
Hash1( x ) = x % 13
Hash2( x ) = 1+(x % 11)
Tabela de hash Hash1( 14 ) = 1
* 0 * 0 Hash2( 14 ) = 4
Hash1( 1 ) = 1
1 1 1 1 Tentativa = 0
* 2 * 2 Posição = 1
1 3 3 1 3 3
Hash( 3 ) = 3
3
? * 4 3 * 4 Tentativa = 1
14 * 5 14 5 14
Posição = 1+4 = 5
27 * 6 27 * 6
* 7 * 7
2 2
* 8 * 8
15 15
* 9 * 9
* 10 * 10
* 11 * 11
* 12 * 12
Algoritmos e Estruturas de Dados F. Sérgio Barbosa
Tabelas de Hash
Duplo hash - exemplo:
Hash1( x ) = x % 13
Hash2( x ) = 1+(x % 11)
Hash1( 27 ) = 1
* 0 Hash2( 27 ) = 6 * 0 Hash1( 2 ) = 2
1 1 Tentativa = 0 1 1
* 2 Posição = 1 2 2
3
1 3 3 1 3
3 * 4 3 * 4
14
14 5 14 14 5
27 * 6 27 * 6
Tentativa = 1
7 27 7 27
2 Posição = 1+6 = 7 2
* 8 * 8
15 15
* 9 * 9
* 10 * 10
* 11 * 11
* 12 * 12
Algoritmos e Estruturas de Dados F. Sérgio Barbosa
26
Tabelas de Hash
Duplo hash - exemplo:
Hash1( x ) = x % 13
Hash2( x ) = 1+(x % 11) Hash1( 15 ) = 2
* 0 Hash2( 15 ) = 5
1 1
2
Tentativa = 0
2 Posição = 2
1 3 3
3 * 4
14 5 14
27 * 6 Tentativa = 1
7 27
2 Posição = 2+5 = 7
* 8
15
* 9
* 10
* 11
12 15 Tentativa = 2
Posição = 2+2*5 = 12
Algoritmos e Estruturas de Dados F. Sérgio Barbosa
// hash normal
int idx = hash1( chave );
27
Tabelas de Hash – Endereçamento livre
Duplo Hashing - inserção:
Em alternativa podia-se usar a seguinte
função, menos versátil, mas mais
optimizada para o duplo hashing
boolean inserir( int chave, Object oElem ) {
int key = hash1( chave );
int passo = hash2( chave );
ParChaveElemento par = new ParChaveElemento( chave, oElem );
Pergunta:
Porque razão a função Hash2 costuma
ter a forma
1 + (x % m)
em vez de
x % m ????
Algoritmos e Estruturas de Dados F. Sérgio Barbosa
28
Tabelas de Hash – Endereçamento livre
Como se efectua a pesquisa no caso de
endereçamento livre?
Determinar a posição onde o elemento
estaria
Se ele lá está (chave tem de ser igual), achou
Se não está lá, é necessário verificar na posição
seguinte
A posição seguinte é determinada de acordo
com a técnica usada na inserção
(obviamente)
Pára-se a procura quando:
Se acha o elemento (chaves iguais)
Se acha uma posição vazia – ele teria de estar até
esta posição inclusive
Se percorre a lista toda
Tabelas de Hash
Sondagem linear – procura - exemplo:
Hash( x ) = x % 13
Tabela de hash Hash( 2 ) = 2
* 0
2? 1 1
2 14 Tentativa = 0 Posição = 2 Chaves diferentes
3 3 Tentativa = 1 Posição = 3 Chaves diferentes
4 27 Tentativa = 2 Posição = 4 Chaves diferentes
5 2 Tentativa = 3 Posição = 5 Chaves Iguais => Encontrou
* 6
* 7
* 8
* 9
* 10
* 11
* 12
Algoritmos e Estruturas de Dados F. Sérgio Barbosa
29
Tabelas de Hash
Sondagem linear – procura - exemplo:
Hash( x ) = x % 13
Tabela de hash Hash( 4 ) = 4
* 0
4? 1 1
2 14
3 3
4 27 Tentativa = 0 Posição = 4 Chaves diferentes
5 2 Tentativa = 1 Posição = 5 Chaves diferentes
* 6 Tentativa = 3 Posição = 6 Posição livre => Não encontrou
* 7
* 8
* 9
* 10
* 11
* 12
Algoritmos e Estruturas de Dados F. Sérgio Barbosa
30
Tabelas de Hash – Endereçamento livre
Como se efectua a remoção de um
elemento no caso de endereçamento
livre?
Será que basta procurar o elemento e
depois colocar a posição a null?
NÃO!! Como se pode ver no exemplo
seguinte
Tabelas de Hash
Sondagem linear – eliminar - exemplo:
Hash( x ) = x % 13
Eliminar 27 Tabela de hash
* 0 * 0
1 1 1 1
2 14 2 14
3 3 3 3
Hash( 27 ) = 1 4 27 * 4
5 2 5 2
* 6 * 6
* 7 * 7
* 8 * 8
* 9 * 9
* 10 * 10
* 11 * 11
* 12 * 12
Algoritmos e Estruturas de Dados 2 F. Sérgio Barbosa
31
Tabelas de Hash
Sondagem linear – eliminar - exemplo:
Hash( x ) = x % 13
3 3
Posição vazia
Hash( 2 ) = 2 * 4
5 2 Não encontra o 2 !!!
* 6
* 7
* 8
* 9
* 10
* 11
* 12 12
Algoritmos e Estruturas de Dados F. Sérgio Barbosa
32
Tabelas de Hash – Endereçamento livre
Como se efectua a remoção de um elemento
no caso de endereçamento livre?
As técnicas anteriores implicam alterar as funções de
inserção e de pesquisa
A de inserção tem de procurar até achar uma posição
com o valor null (vazia) ou com a indicação de estar
apagada (APAGADO ou a chave especial)
A de pesquisa tem de procurar até achar o elemento ou
uma posição com o valor null e ignorar as posições
apagadas
Isto significa que se houver muitas remoções se
pode pesquisar a tabela toda só para determinar que
um elemento não está lá
Por esta razão as tabelas de endereçamento livre são
pouco usadas quando a remoção de elementos é
frequente
33