Sei sulla pagina 1di 36

Tabelas Hash

Prof. Thales Castro


Motivao
Dada uma tabela com uma chave e vrios valores por linha,
quero rapidamente procurar, inserir e apagar registros baseados
nas suas chaves
Estruturas de busca sequencial/binria levam tempo at
encontrar o elemento desejado.
Ex: Arrays e listas Ex: rvores
5 2 6 1 7 8 4 9
5 2 6 1 4
8
2
6
4
1
9
Motivao
Em algumas aplicaes, necessrio obter o valor
com poucas comparaes, logo, preciso saber a
posio em que o elemento se encontra, sem precisar
varrer todas as chaves.
A estrutura com tal propriedade chamada de tabela
hash.
64 11 20 7
0 1 2 3 4 5 6 7
20 ?
20 mod 8 = 4
20 45 ?
45 mod 8 = 5
11 ?
11 mod 8 = 3
11
Funes Hashing
Os registros com as chaves so armazenados nessa
tabela, e endereados a partir de uma funo de
transformao sobre a chave de pesquisa
A essa funo d-se o nome de Funo HASHING
Seja M o tamanho da tabela:
A funo de hashing mapeia as chaves de entrada em
inteiros dentro do intervalo [1..M]
Formalmente:
A funo de hashing h(k
j
) [1,M] recebe uma chave
k
j
{k
0
,..,k
m
} e retorna um nmero i, que o ndice do
subconjunto m
i
[1,M] onde o elemento que possui essa
chave vai ser manipulado


Funes Hashing
Mtodo pelo qual:
As chaves de pesquisa so transformadas em endereos
para a tabela (funo de transformao);
Obtm-se valor do endereo da chave na tabela HASH
Tal funo deve ser fcil de se computar e fazer uma
distribuio equiprovvel das chaves na tabela
Existem vrias funes Hashing, dentre as quais:
Resto da Diviso
Meio do Quadrado
Mtodo da Dobra
Mtodo da Multiplicao
Hashing Universal

Resto da Diviso
Forma mais simples e mais utilizada
Nesse tipo de funo, a chave
interpretada como um valor numrico que
dividido por um valor
O endereo de um elemento na tabela dado
simplesmente pelo resto da diviso da sua
chave por M (F
h
(x) = x mod M), onde M o
tamanho da tabela e x um inteiro
correspondendo chave
0 <= F(x) <= M
Resto da Diviso

Ex: M=1001 e a seqncia de chaves: 1030, 839,
10054 e 2030
Chave Endereo
1030 29
10054 53
839 838
2030 29


Resto da Diviso Desvantagens
Funo extremamente dependente do valor
de M escolhido
M deve ser um nmero primo
Valores recomendveis de M devem ser >20
Funes Hash
Seja qual for a funo, na prtica existem
sinnimos chaves distintas que resultam em
um mesmo valor de hashing.
Quando duas ou mais chaves sinnimas so
mapeadas para a mesma posio da tabela, diz-
se que ocorre uma coliso.

Tratamento de Colises
Algumas solues conhecidas
Tabelas Hash- Colises
Qualquer que seja a funo de transformao,
existe a possibilidade de colises, que devem ser
resolvidas, mesmo que se obtenha uma
distribuio de registros de forma uniforme;
Tais colises devem ser corrigidas de alguma
forma;
O ideal seria uma funo HASH tal que, dada
uma chave 1 <= I <= 26, a probabilidade da
funo me retornar a chave x seja PROB(F
h
(x)=
I) = 1/26, ou seja, no tenha colises, mas tal
funo difcil, se no impossvel
O valor de h(k) o
mesmo para 1030 e
2030: coliso
Resto da Diviso - Coliso
No exemplo dado, M=1001 e a seqncia de
chaves: 1030, 839, 10054 e 2031

Chave Endereo
1030 29
10054 53
839 838
2030 29


Tratamento de Colises
Alguns dos algoritmos de Tratamento de
Colises so:
Endereamento Fechado
Endereamento Aberto
Hashing Linear
Hashing Duplo
Endereamento Fechado
Tambm chamado de Overflow Progressivo
Encadeado
Algoritmo: usar uma lista encadeada para cada
endereo da tabela
Vantagem: s sinnimos so acessados em uma
busca. Processo simples.
Desvantagens:
necessrio um campo extra para os ponteiros de ligao.
Tratamento especial das chaves: as que esto com endereo
base e as que esto encadeadas

Endereamento Fechado
No endereamento fechado, a posio de insero
no muda. Todos devem ser inseridos na mesma
posio, atravs de uma lista ligada em cada uma.
0
1
2
3
4
20 mod 5 = 0
20
18 mod 5 = 3
18
25 mod 5 = 0
coliso com 20
25
Endereamento Fechado
Program TabelaHash;
Const n = 50;
Type Ponteiro = ^no;
Type no = record
item: integer;
prox: Ponteiro;
End;
Var posicoes: array [1..n] of Integer;
Procedure Inicia_Hash;
Var i: integer;
Begin
for i:=1 to n do
posicoes[i] := nil;
End;
A tabela hash, neste caso,
contm um array de listas
ligadas
Endereamento Fechado
Quando uma chave for inserida, a funo hash aplicada, e ela
acrescentada lista adequada
Procedure inserir(chave: integer);
Var i: integer; aux: ponteiro;
Begin
i := hashCode(chave);
aux := lista[i];
if aux = nil then begin
new[lista[i]];
lista[i] := chave;
lista[i].^.prox := nil;
end else begin
while aux^.prox <> nil do
aux := aux^.prox;
new(aux^.prox);
aux := aux^.prox;
aux^.prox := nil;
aux^.item := chave;
End;
End;
Assume-se que a funo hash
est implementada
/*Caso em que no existe o registro na
posio ainda*/
Endereamento Fechado
A busca feita do mesmo modo: calcula-se o valor da
funo hash para a chave, e a busca feita na lista
correspondente.
Se o tamanho das listas variar muito, a busca pode se tornar
ineficiente, pois a busca nas listas se torna seqencial
0
1
2
3
20 4 0 88 32
15 11
60
Endereamento Fechado
obrigao da funo HASH distribuir as chaves entre
as posies de maneira uniforme
0
0 1 2 3 4 5 6
15 10
31
4
88
13
20
Hashing Linear
Tambm conhecido como Overflow Progressivo
Consiste em procurar a prxima posio vazia
depois do endereo-base da chave
Vantagem: simplicidade
Desvantagem: se ocorrerem muitas colises, pode
ocorrer um clustering (agrupamento) de chaves
em uma certa rea. Isso pode fazer com que sejam
necessrios muitos acessos para recuperar um
certo registro. O problema vai ser agravado se a
densidade de ocupao para o arquivo for alta
Hashing Linear
64 11 20 7
0 1 2 3 4 5 6 7
27 ?
27 mod 8 = 3
11 20 27
Hashing Linear - Implementao
A tabela hash, neste caso, contm um array de objetos,
e posies vazias so indicadas por -1. Neste caso, os
objetos sero do tipo Integer:
Program TabelaHash;
Const n = 50;
Var posicoes: array [1..n] of Integer;
Procedure Inicia_Hash;
Var i: integer;
Begin
for i:=1 to n do
posicoes[i] := -1;
End;
Hashing Linear - Implementao
Na insero, a funo hash calculada, e a posio
incrementada, at que uma posio esteja livre
Procedure inserir(chave: integer;) {
Var i: integer;
Begin
i := FuncaoHash(chave);
while (posicoes[i] <> -1)
i := (i + 1) mod n;
posicoes[i] := chave;
End;
Tambm assume-se
que a funo hash
est implementada
Hashing Linear
Valores: 52, 78, 48, 61, 81, 120, 79, 121, 92
Funo: hash(k) = k mod 13
Tamanho da tabela: 13
0 1 2 3 4 5 6 7 8 9 10 11 12
52
52
78
78 48
48
61
61
81
81
120
120
79
79
121
121
92
92
Hashing Duplo
Tambm chamado de re-hash
Ao invs de incrementar a posio de 1, uma
funo hash auxiliar utilizada para calcular o
incremento. Esta funo tambm leva em conta o
valor da chave.
Vantagem: tende a espalhar melhor as chaves pelos
endereos.
Desvantagem: os endereos podem estar muito
distantes um do outro (o princpio da localidade
violado), provocando seekings adicionais
Hashing Duplo
64 11 20 53 7
0 1 2 3 4 5 6 7
27 ?
H(27) = 27 mod 8 = 3
11 27
Inc(27) = 27*4+7 = 115
(3 + 115) mod 8 = 6
Hashing Duplo - Implementao
A estrutura semelhante ao Hashing Linear: um vetor
de chaves
Program TabelaHash;
Const n = 50;
Var posicoes: array [1..n] of Integer;
Procedure Inicia_Hash;
Var i: integer;
Begin
for i:=1 to n do
posicoes[i] := -1;
End;
Hashing Duplo - Implementao
Na insero, a funo hash calculada. Caso exista
conflito, chama-se uma funo hash alternativa at que
uma posio esteja livre
Procedure inserir(chave: integer);
Var i: integer;
Begin
i := FuncaoHash(chave);
while (posicoes[i] <> -1)
i := FunoHash_Alternativa(chave);
posicoes[i] := chave;
End;
Assume-se que essas
funes esto
implementadas
Endereamento Aberto
Remoo
Para fazer uma busca com endereamento aberto, basta
aplicar a funo hash, e a funo de incremento at que
o elemento ou uma posio vazia sejam encontrados.
Porm, quando um elemento removido, a posio
vazia pode ser encontrada antes, mesmo que o
elemento pertena a tabela:
64 11 20 7
Insero do 27
Remoo do 20
Busca pelo 27
11 27 20 11 27
27? No
11
Fim da busca? Sim
Endereamento Aberto: Remoo
Para contornar esta situao, mantemos um bit (ou um
campo booleano) para indicar que um elemento foi
removido daquela posio:
64 11 20 7 11 27 20 X 11 27
27? No
11
Fim da busca? No
X 27
Esta posio estaria livre para uma nova insero, mas
no seria tratada como vazia numa busca.
Tabelas HASH Dinmica
64 1 2 11 4 9 7
Endereamento Aberto
Expanso
Na poltica de hashing, h que chamamos de fator de
carga (load factor). Ele indica a porcentagem de
clulas da tabela hash que esto ocupadas, incluindo as
que foram removidas.
Quando este fator fica muito alto (ex: excede 50%), as
operaes na tabela passam a demorar mais, pois o
nmero de colises aumenta.
9 ?
1 2 11 4 9
Tamanho = 13
Endereamento Aberto
Expanso
Quando isto ocorre, necessrio expandir o array que
constitui a tabela, e reorganizar os elementos na nova
tabela. Como podemos ver, o tamanho atual da tabela
passa a ser um parmetro da funo hash.
34 40 X 11 95
34 40 11 95
Tamanho = 7
Endereamento Aberto
Expanso
O problema : Quando expandir a tabela?
O momento de expandir a tabela pode variar
Quando no for possvel inserir um elemento
Quando metade da tabela estiver ocupada
Quando o load factor atingir um valor escolhido
A terceira opo a mais comum, pois um meio
termo entre as outras duas.
Quando no usar Hashing?
Muitas colises diminuem muito o tempo de acesso e
modificao de uma tabela hash. Para isso necessrio
escolher bem:
- a funo hash
- o algoritmo de tratamento de colises
- o tamanho da tabela
Quando no for possvel definir parmetros eficientes,
pode ser melhor utilizar rvores balanceadas (como
AVL), em vez de tabelas hash.
FIM