Hashing
Prof. Josenildo Silva
[email protected]
IFMA
2012
Esta versão é de 2012.11.21
© 2012, Prof. Josenildo Silva. ([email protected])
Estas notas de aula foram preparadas por Josenildo Silva para a disciplina
Análise e Projeto de Algoritmos do Programa de Mestrado Profissional
IFMA/UEMA baseado nas notas de aulas do Prof. Omar Andres Carmona
Cortes. Fica aqui permitida a utilização, cópia, modificação e distribuição
destas notas para propósitos educacionais, desde que esta nota de copyright
seja mantida em todas as cópias.
Introdução
 Estruturas de busca seqüencial/binária levam
tempo O(n) até encontrar o elemento
desejado
 Em uma árvore o tempo de busca é em torno
de O(lg n)
 Muitas vezes é necessário encontrar a posição
de um elemento em tempo O(1) (perfeita) no
melhor caso e O(n) (muitas colisões) no pior
caso
o Utilizar uma tabela Hash
Tabelas Hash
 Operações suportadas
o inserir(k)
o buscar(k)
o remover(k)
Tabelas Hash
 Uma tabela hash é uma estrutura de dados
que permite acesso a elementos em tempo
O(1) dada uma função de hashing
 Exemplo usando a função mod
20 mod 8 = 4
0
20?
1
2
64
11?
11 mod 8 = 3
3
4
11
20
5
6
7
7
Função de Hashing
 O endereço ou índice que um elemento é
armazenado é encontrado através de uma função
de transformação
o Função de Hashing
 Seja M o tamanho da tabela, a função de hashing
mapeia as chaves de entrada dentro do intervalo
[1...M]
 Formalmente h(kj) [1,M], onde
o kj {k0, ..., km},
o sendo que h retorna mi  [1,M]
Funções de Hashing
 A função deve ser fácil de se computar para não
comprometer o desempenho
 A função deve também fazer uma distribuição
uniforme dentre os índices disponíveis
 Colisões sempre irão ocorrer
 Funções mais comuns
o
o
o
o
Resto da divisão (mod)
Método da multiplicação
Hashing Universal
Hashing Perfeito
Método do Resto da Divisão
Resto da Divisão (MOD)
 Forma mais simples de ser utilizada
 O endereço de armazenamento ou
consulta é o resto da divisão da sua chave
por M, onde M é o tamanho da tabela e x
um número inteiro
o h(x) = x mod M para mi  [0, M-1]
 O resultado estará no intervalo [0, M-1]
Resto da Divisão (MOD)
 Exemplo
o Considere um vetor de tamanho 1001 para
armazenamento e a seqüência de chaves: 1030, 839,
10054 e 2030
o Os respectivos endereços (índices serão)
Chave
1030
10054
839
2030
Endereço (mod 1001)
29
53
839
28
Resto da Divisão (MOD)
 Vantagens
o Fácil de computar
o Rápida
 Desvantagens
o Função depende do valor de M
o M deve ser um número primo
o M > 20
o Alta probabilidade de colisões
Método da Multiplicação
Método da Multiplicação
 Funciona do seguinte modo
o
o
o
o
Multiplica-se a chave k por uma constante A, onde A  [0,1]
Extrai-se o resto da multiplicação com kA mod 1
Multiplique o resultado por m, o tamanho da tabela
Finalmente
 h(k) = m (kA mod 1)
 A escolha de m não é crítico
 Sugere-se A = 0.6180339887
o (D. Knuth “The Art of Programming”)
 Para facilitar a implementação m deve ser uma potência de 2
Método da Multiplicação
 Exemplo: dado um m = 100, a tabela a
seguir mostra onde as chaves serão
inseridas
Chave
1000
2000
3500
150
10
18
h(x)
3
6
11
70
18
12
Chave
25
32
136
357
211
896
h(x)
45
77
5
63
40
75
Hashing Universal
 Com funções de hashing “fixas” é possível prever as
colisões para um conjunto dado de entradas
o Solução: Criar funções de hashing aleatórias
independentes das chaves baseando-se em pesos
aleatórios
 Seja U o universo de chaves e H um conjunto finito de
funções de hashing, onde u  U  {0, 1, ..., m-1}
 H é universal se  x,y  U, onde x  y, {H: h(x) = h(y)} =
H/m
o Escolhendo h aleatoriamente a probabilidade de haver
uma colisão é 1/m
Hashing Universal
 Os pesos são iniciados aleatoriamente a
cada execução do programa, mas
permanecem inalterados até o fim da
execução.
Hashing Universal
 No caso de strings de tamanho n
n 1
K   chave[i ]  p[i];
i 0
h( K )  K mod M
Hashing Universal
Hashing Perfeito
 Transforma/mapeia um conjunto de chaves
xj, 1  xj  N em um conjunto de inteiros no
intervalo 0  h(xj)  M-1
 Ocorrerá h(xi) = h(xj) se e somente se xi = xj
 Se N=M então tem-se uma função de
transformação perfeita mínima
 Se xi < xj e h(xi) < h(xj) temos uma função de
transformação perfeita mínima com ordem
preservada
Hashing Perfeito
Tratamento de Colisões
 Sempre há a possibilidade de colisões, exceto
para as funções de hashing perfeito
 Existem possibilidade para tratar as colisões
dependendo da forma como a tabela hash é
construída
o Endereçamento Aberto
 Hashing Linear
 Hashing Duplo
o Endereçamento Fechado
Endereçamento Aberto – Hashing
Linear
 No hashing linear busca-se a próxima posição
vazia depois do endereço da chave
 Vantagem: simplicidade
 Desvantagem: a inserção e busca passam a ter
desempenho O(n)
27 mod 8 = 3
0
27?
64
1
2
3
4
11
20
5
6
7
7
Endereçamento Aberto - Hashing
Linear
 Implementação
 A função é calculada até que uma posição
livre seja encontrada
void inserir(Chave ch, Table HashTable){
inteiro i;
i = h(ch); //calculo de endereço
enquanto (HashTable[i] ocupado)
i = (i + 1) mod n;
HashTable[i] = ch;
}
 A busca é feita de modo análogo
Hashing Duplo
 Também chamado de re-hash
 Ao invés de incrementar a posição em 1, uma outra função
de hash auxiliar é utilizada
o h(i,k) = (h1(k) + i * h2(k)) mod M
 Restrições
o M deve ser uma potência de 2
o h2 deve ser sempre ímpar
 Exemplo
o h1(k) = k + 37; // usando número primo
o h2(k) = k + 31; se h2 é ímpar
o h2(k) = (k + 31) + 1; se h2 é par
Hashing Duplo
 Exemplo
h1 = 27 + 37 = 64
h = (64 + 0 * 59) mod 8 = 0
h2 = (27 + 31) + 1 = 59
0
27?
64
1
2
3
4
11
20
5
6
7
7
h = (64 + 1 * 59) mod 8 = 123 mod 8 = 3
h = (64 + 2 * 59) mod 8 = 182 mod 8 = 6
Implementação em C:
http://www.youtube.com/watch?v=272lg-fhklE&feature=related
Fator de Carga
 Quando utilizamos o endereçamento
aberto a medida que inserimos mais
elementos o desempenho da tabela hash
cai, pois ocorrem mais colisões
 O fator de carga  é definido como n/m
 Se o fator de carga é alto então deve-se
expandir a tabela hash
Endereçamento Fechado
 Também chamado de Overflow Progressivo
Encadeado
 Utiliza-se uma lista encadeada para cada
endereço da tabela
 Vantagem
o Não é preciso recalcular endereços
o “Sinônimos” são encontrados em uma única busca
 Desvantagem
o Tratamento em listas pode consumir tempo O(n)
Endereçamento Fechado
 Usando o método tradicional de hashing inserimos os
elementos 20, 25, 36, 39, 41, 51, 60, 61
0
20 mod 8 = 4
25 mod 8 = 1
36 mod 8 = 4
39 mod 8 = 7
41 mod 8 = 1
51 mod 8 = 3
60 mod 8 = 4
61 mod 8 = 5
1
2
3
4
5
6
7
25
41
51
20
61
39
36
60
Exercícios
 Implemente o algoritmo de hashing linear
tradicional com tamanho M e N elementos (M >
N)
o Insira N – 1 elementos e verifique a média de
colisões
o Faça uma expansão quando  for 0.8, insira mais N/2
elementos e verifique a média de colisões
 Faça as mesmas operações acima usando o
Hashing Universal e obtenha as mesmas medidas
Exercícios
 Dado uma tabela hash de 170 posições e um domínio de chaves
no intervalo [1, 1000], com 150 chaves, implemente um programa
que encontre pelo menos 4 colisões usando:
o Resto da divisão
o Multiplicação
 Implemente um programa que armazene 100 chaves quaisquer
em um vetor de 130 posições e expanda a tabela hash quando a
carga for igual a 60%.
 Verifique o desempenho necessário para expandir uma tabela
hash de 10.000 para 30.000 usando o hashing universal, com:
o 5000 chaves
o 9000 chaves
Referências
 Slides do Prof. Omar Carmona
 CORMEN, 3ª. Ed.
 SEDGEWICK, Algorithms. Sec. 3.4
 Slides do Prof. Paulo Feofiloff (IME, USP)
Download

Hashing - DAI