Você está na página 1de 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
5 2 6 1 7 8 4 9

Ex: rvores 8 2 9 6 4

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.
20 mod 8 = 4
0 1 2 3 4 5 6

45 mod 8 = 5
7

20 ? 11 ?

64
11 mod 8 = 3

11 20

45 ?

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(kj) p [1,M] recebe uma chave kj {k0,..,km} e retorna um nmero i, que o ndice do subconjunto mi [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 (Fh(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, dizse 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(Fh(x)= I) = 1/26, ou seja, no tenha colises, mas tal funo difcil, se no impossvel

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

O valor de h(k) o mesmo para 1030 e 2030: coliso

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.
20 mod 5 = 0 18 mod 5 = 3 25 mod 5 = 0 coliso com 20
0 1 2 3 4

20

25

18

Program TabelaHash; Const n = 50;

Endereamento Fechado
A tabela hash, neste caso, contm um array de listas ligadas

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;

Quando uma chave for inserida, a funo hash aplicada, e ela acrescentada lista adequada Procedure inserir(chave: integer); Var i: integer; aux: ponteiro; Begin Assume-se que a funo hash i := hashCode(chave); est implementada aux := lista[i]; /*Caso em que no existe o registro na if aux = nil then begin posio ainda*/ 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;

Endereamento Fechado

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

88

32

60

15

11

Endereamento Fechado
obrigao da funo HASH distribuir as chaves entre as posies de maneira uniforme
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
27 mod 8 = 3
0 1 2 3 4 5 6 7

27 ?

64

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; Tambm assume-se Begin que a funo hash i := FuncaoHash(chave); est implementada while (posicoes[i] <> -1) i := (i + 1) mod n; posicoes[i] := chave; End;

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 78 79 81 120 121 92

48 61

78 92 52 79

120 121 81

48 61

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
Inc(27) = 27*4+7 = 115 (3 + 115) mod 8 = 6 H(27) = 27 mod 8 = 3
0 1 2 3 4 5 6 7

27 ?

64

11 20 53 27 7

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); Assume-se que essas funes esto implementadas

while (posicoes[i] <> -1) i := FunoHash_Alternativa(chave); posicoes[i] := chave; End;

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:
27? No Insero do 27 Remoo do 20

64

11 20 27

Busca pelo 27

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:
27? No

64

11 20 27 X

Fim da busca? No

Esta posio estaria livre para uma nova insero, mas no seria tratada como vazia numa busca.

Tabelas HASH Dinmica

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? 64 1 2 11 4 9 7

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
Tamanho = 7 Tamanho = 13

40

95

34

11

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

Você também pode gostar