Sie sind auf Seite 1von 15

LEIC-FEUP 2001/2002

Algoritmos e Estruturas de Dados 1

Tabelas de Dispersão (Hash Tables)

q Sumário

l Definição. Características.
l Resolução de colisões: dispersão aberta e dispersão fechada. Teste quadrático.
l Desempenho de tabelas de dispersão.
l Interface de tabela de dispersão.
l Implementação de tabela de dispersão fechada com teste quadrático.

HASH (v2) - 1

Tabela de Dispersão
q Árvores binárias (de pesquisa) simples
l pior caso nas operações de manipulação é O(N)
l pior caso surge sistematicamente em usos correntes (ex: elementos previamente
ordenados)

q Tabela de dispersão
l pesquisa baseada na geração de um inteiro a partir da chave
l tempo médio constante para inserção, remoção e pesquisa
l não requer gestão de memória especial nem comparação de elementos
l ocorrência do pior caso tem probabilidade muito baixa

q Aplicações
l tabelas de símbolos dos compiladores

HASH (v2) - 2

Cristina Ribeiro Hash- 1


LEIC-FEUP 2001/2002
Algoritmos e Estruturas de Dados 1

Resolver colisões - dispersão com listas


q Manter lista de elementos colocados na mesma entrada
l 1 lista com cabeçalho em cada entrada da tabela
l escolhe-se inserção a ocorrer na cabeça ou na cauda da lista
l exemplo com função de dispersão hash(x) = x mod 10 e inserção na cauda:

0 0

1 1 81

2
{0, 1, 4, 81, 64} 3
1º último 4 4 64
5

6
7
8
9

HASH (v2) - 3

Resolver colisões - dispersão aberta


q Perante colisão procura-se célula alternativa
l Tenta-se sequência de células H0 (x), H1 (x), H2 (x), ...
l Hi (x) = ( hash(x) + f(i) ) mod TamanhoTabela

q Teste linear: procurar sequencialmente a partir de H0


l primeira posição livre a seguir à inicial H0 é usada
- tenta-se H0+1, H 0+2, ...
l pesquisa “dá a volta” no fim da tabela
l f(i) = i

q Teste quadrático
l procurar próxima posição livre a seguir a H com passo quadrático
- tenta-se H0+12, H 0 + 22, H0 + 32, ...
l é preciso garantir que se pode percorrer a tabela toda - ver adiante
HASH (v2) - 4
l f(i) = i2

Cristina Ribeiro Hash- 2


LEIC-FEUP 2001/2002
Algoritmos e Estruturas de Dados 1

Desempenho na dispersão com listas


q Factor de carga λ
l razão entre o número de elementos na tabela e o tamanho da tabela

q Dispersão com listas


l comprimento médio de cada lista é λ
l tempo médio de pesquisa: avaliação da função de dispersão + percurso na lista
- pesquisa sem sucesso: número médio de ligações a percorrer é λ
- pesquisa com sucesso: número médio de ligações a percorrer é 1 + λ/2
l bom desempenho para λ pró ximo de 1

HASH (v2) - 5

Desempenho na Dispersão Aberta (1)


q Dispersão aberta
l com função linear λ= 0.2
Ins, Falha: 1.3
- número de tentativas para inserção e para pesquisa sem Sucesso: 1.1
sucesso:
λ= 0.8
1/2 ( 1 + 1/(1- λ)2 ) Ins, Falha: 13
- número de tentativas para pesquisa com sucesso: Sucesso: 3
1/2 ( 1 + 1/(1- λ) )
l caso ideal (sem clustering)
λ= 0.2
- número de tentativas para inserção e para pesquisa sem Ins, Falha: 1.3
sucesso:
Sucesso: 1.1
1/(1- λ)
λ= 0.8
- número de tentativas para pesquisa com sucesso: Ins, Falha: 5.0
1/ λ ln (1/(1- λ) ) Sucesso: 2.0
l função quadrática elimina clustering primário
- na prática, eficiência próxima do caso ideal

HASH (v2) - 6

Cristina Ribeiro Hash- 3


LEIC-FEUP 2001/2002
Algoritmos e Estruturas de Dados 1

Desempenho na Dispersão Aberta (2)


10000
nº de posições acedidas para
inserção e pesquisa

1000 função linear, elemento


inexistente

função linear, elemento


100 existente

caso ideal (sem


clustering), elemento
13 inexistente
10 caso ideal (sem
5 clustering), elemento
3
existente
2
1
0,0 0,1 0,2 0,3 0,4 0,5 0,6 0,7 0,8 0,9 1,0 com dispersão aberta, o factor de
carga não deve exceder 0,5 para
factor de carga
se garantir um bom desempenho!

HASH (v2) - 7

Dispersão com Teste Quadrático


q Teorema
Usando teste quadrático e uma tabela cujo tamanho é um número primo, um
novo elemento pode sempre ser inserido se a tabela não estiver preenchida a
mais de 50%
-Mostra-se que as primeiras Tam/2 posições alternativas são todas distintas,
por redução ao absurdo
h(x) + i2 (mod Tam) = h(x) + j2 (mod Tam) com i≠j e 0 < i,j < Tam/2 
h(x) + i2 = h(x) + j2 (mod Tam)
i2 = j2 (mod Tam)
i2 - j2 = 0 (mod Tam)
( i-j )( i+j ) = 0 (mod Tam) (o mesmo que ( i-j )( i+j ) = k Tam)
Sendo Tam número primo, ( i-j ) ou ( i+j ) tem de ser 0 (mod Tam). Sendo i e j
distintos, ( i-j ) não é 0; sendo 0 < i,j < Tam/2, ( i+j ) também não é 0. Então as
primeiras Tam/2 posições alternativas são distintas

HASH (v2) - 8

Cristina Ribeiro Hash- 4


LEIC-FEUP 2001/2002
Algoritmos e Estruturas de Dados 1

Dispersão com Teste Quadrático


q Teorema
A geração de posições alternativas no teste quadrático pode ser feita com
apenas uma multiplicação
Seja H0 a posição inicial, Hi-1 a última posição calculada e Hi a próxima
Hi = H0 + i2 (mod Tam)
Hi - Hi-1 = i2 - (i-1)2 (mod Tam)
Hi = Hi-1 + 2i - 1 (mod Tam)
O valor de Hi pode assim ser obtido sem operações pesadas de multiplicação
Para calcular o mod:
2i-1 é menor que Tam
Hi-1 + 2i - 1 ou é menor que Tam (caso em que o mod se dispensa)
ou é pouco maior que Tam (caso em que o mod se reduz a
subtrair Tam)

HASH (v2) - 9

Eliminação com Dispersão Aberta


q Para eliminar um elemento da tabela, marca-se como apagado, para que
posteriores pesquisas funcionem correctamente
q 3 estados: posição ocupada, livre ou marcada como apagada
l posição activa: ocupada ou marcada como apagada
q Exemplo, com hash(x) = x mod 10
0 0 0 0

1 1 1 1 como a
posição
2 2 2 2
add(13) add(23) remove(13) contains(23) está
3 13 3 13 3 13 3 13 marcada
4 4 4 4 como
23 23 23
marca apagada,
5 5 5 5 procura na
posição
como posição
6 6 6 6
apagada seguinte
7 7 7 7

8 8 8 8

9 9 9 9

HASH (v2) - 10

Cristina Ribeiro Hash- 5


LEIC-FEUP 2001/2002
Algoritmos e Estruturas de Dados 1

Tabela de Dispersão em HashSet


package weiss.util;
import java.io.Serializable;
public class HashSet extends AbstractCollection implements Set
{
private static final int DEFAULT_TABLE_SIZE = 101;
private int currentSize = 0;
private int occupied = 0;
private int modCount = 0;
private HashEntry [ ] array;
public HashSet( )
{
allocateArray( DEFAULT_TABLE_SIZE );
clear( );
}
public HashSet( Collection other )
{
allocateArray( other.size( ) * 2 );
clear( );
Iterator itr = other.iterator( );
while( itr.hasNext( ) )
add( itr.next( ) );
}

HASH (v2) - 11

Tabela de Dispersão em HashSet


public int size( )
{
return currentSize;
}

/**
* This method is not part of standard Java 1.2.
* Like contains, it checks if x is in the set.
* If it is, it returns the reference to the matching
* object; otherwise it returns null.
*/
public Object getMatch( Object x )
{
int currentPos = findPos( x );
if( array[ currentPos ] == null )
return null;
return array[ currentPos ].element;
}

HASH (v2) - 12

Cristina Ribeiro Hash- 6


LEIC-FEUP 2001/2002
Algoritmos e Estruturas de Dados 1

Tabela de Dispersão em HashSet


/**
* Tests if some item is in this collection.
* @param x any object.
* @return true if this collection contains an item equal to x.
*/
public boolean contains( Object x )
{
return isActive( array, findPos( x ) );
}

/**
* Tests if item in pos is active.
* @param pos a position in the hash table.
* @param arr the HashEntry array (can be oldArray during rehash).
* @return true if this position is active.
*/
private static boolean isActive( HashEntry [ ] arr, int pos )
{
return arr[ pos ] != null && arr[ pos ].isActive;
}

HASH (v2) - 13

Tabela de Dispersão em HashSet

/**
* Adds an item to this collection.
*/
public boolean add( Object x )
{
int currentPos = findPos( x );
if( isActive( array, currentPos ) )
return false;

array[ currentPos ] = new HashEntry( x, true );


currentSize++;
occupied++;
modCount++;

if( occupied > array.length / 2 )


rehash( );

return true;
}

HASH (v2) - 14

Cristina Ribeiro Hash- 7


LEIC-FEUP 2001/2002
Algoritmos e Estruturas de Dados 1

Tabela de Dispersão em HashSet


/**
* Private routine to perform rehashing.
* Can be called by both add and remove.
*/
private void rehash( )
{
HashEntry [ ] oldArray = array;

// Create a new, empty table


allocateArray( nextPrime( 4 * size( ) ) );
currentSize = 0;
occupied = 0;

// Copy table over


for( int i = 0; i < oldArray.length; i++ )
if( isActive( oldArray, i ) )
add( oldArray[ i ].element );
}

HASH (v2) - 15

Tabela de Dispersão em HashSet


/**
* Removes an item from this collection.
*/
public boolean remove( Object x )
{
int currentPos = findPos( x );
if( !isActive( array, currentPos ) )
return false;

array[ currentPos ].isActive = false;


currentSize--;
modCount++;

if( currentSize < array.length / 8 )


rehash( );

return true;
}

HASH (v2) - 16

Cristina Ribeiro Hash- 8


LEIC-FEUP 2001/2002
Algoritmos e Estruturas de Dados 1

Tabela de Dispersão em HashSet

public void clear( )


{
currentSize = occupied = 0;
modCount++;
for( int i = 0; i < array.length; i++ )
array[ i ] = null;
}

public Iterator iterator( )


{
return new HashSetIterator( );
}

HASH (v2) - 17

Tabela de Dispersão em HashSet

private class HashSetIterator implements Iterator


{
private int expectedModCount = modCount;
private int currentPos = -1;
private int visited = 0;

public boolean hasNext( )


{
if( expectedModCount != modCount )
throw new ConcurrentModificationException( );

return visited != size( );


}

HASH (v2) - 18

Cristina Ribeiro Hash- 9


LEIC-FEUP 2001/2002
Algoritmos e Estruturas de Dados 1

Tabela de Dispersão em HashSet

public Object next( )


{
if( !hasNext( ) )
throw new NoSuchElementException( );

do
{
currentPos++;
} while( currentPos < array.length &&
!isActive( array, currentPos ) );

visited++;
return array[ currentPos ].element;
}

HASH (v2) - 19

Tabela de Dispersão em HashSet

public void remove( )


{
if( expectedModCount != modCount )
throw new ConcurrentModificationException( );
if( currentPos == -1 ||
!isActive( array, currentPos ) )
throw new IllegalStateException( );

array[ currentPos ].isActive = false;


currentSize--;
visited--;
modCount++;
expectedModCount++;
}
}

HASH (v2) - 20

Cristina Ribeiro Hash- 10


LEIC-FEUP 2001/2002
Algoritmos e Estruturas de Dados 1

Tabela de Dispersão em HashSet

private static class HashEntry implements Serializable


{
public Object element; // the element
public boolean isActive; // false if marked deleted

public HashEntry( Object e )


{
this( e, true );
}

public HashEntry( Object e, boolean i )


{
element = e;
isActive = i;
}
}

HASH (v2) - 21

Tabela de Dispersão em HashSet


private int findPos ( Object x )
{
int collisionNum = 0;
int currentPos = ( x == null ) ? 0
: Math.abs ( x.hashCode ( ) % array.length );

while( array[ currentPos ] != null )


{
if( x == null )
{
if( array[ currentPos ].element == null )
break;
}
else if( x.equals( array[ currentPos ].element ) )
break ;

currentPos += 2 * ++collisionNum - 1; // Compute ith probe


if( currentPos >= array.length ) // Implement the mod
currentPos -= array.length;
}

return currentPos;
}

HASH (v2) - 22

Cristina Ribeiro Hash- 11


LEIC-FEUP 2001/2002
Algoritmos e Estruturas de Dados 1

Tabela de Dispersão em HashSet

private void allocateArray( int arraySize )


{
array = new HashEntry[ arraySize ];
}

private static int nextPrime( int n )


{
if( n % 2 == 0 )
n++;

for( ; !isPrime( n ); n += 2 )
;

return n;
}

HASH (v2) - 23

Tabela de Dispersão em HashSet

private static boolean isPrime( int n )


{
if( n == 2 || n == 3 )
return true;

if( n == 1 || n % 2 == 0 )
return false;

for( int i = 3; i * i <= n; i += 2 )


if( n % i == 0 )
return false;

return true;
}
}

HASH (v2) - 24

Cristina Ribeiro Hash- 12


LEIC-FEUP 2001/2002
Algoritmos e Estruturas de Dados 1

Implementação de Dicionários (maps


(maps))
com Tabelas de Dispersão (1)
q Um dicionário, ou função finita definida em extensão (map), é um
conjunto de pares (chave, valor) tal que não existem dois pares
com chaves iguais
l Tanto a chave como o valor podem ser de um tipo arbitrariamente complexo
l Exemplo: chave – nº da conta; valor – nome do dono da conta
- É função (finita): chave valor

{ (1, "João"), (3, "João"), (5, "Rui")} x x


x
x x

- Não é função (finita)


chave valor
{ (1, "João"), (1, "Ana "), (5, "Rui")} x
x
x
x x
(mas é uma relação binária)

HASH (v2) - 25

Implementação de Dicionários (maps


(maps))
com Tabelas de Dispersão (2)
q Implementação com tabela de dispersão (classe HashMap)
l um elemento da tabela é um par (chave, valor) (classe Pair)
l a função de dispersão (hashCode) e a função de comparação (equals)
baseiam-se apenas na chave do par
l as funções de pesquisa (containsKey, get) e eliminação (remove) têm
como argumento a chave
- funções implementadas na classe abstracta MapImpl
l a função de inserção (put) tem como argumentos a chave e o valor
- função implementada na classe abstracta MapImpl
l pode-se modificar o valor correspondente a uma dada chave (put)
- função implementada na classe abstracta MapImpl

HASH (v2) - 26

Cristina Ribeiro Hash- 13


LEIC-FEUP 2001/2002
Algoritmos e Estruturas de Dados 1

Tabela de Dispersão em HashMap

package weiss.util;

/**
* Hash table implementation of the Map.
*/
public class HashMap extends MapImpl
{

public HashMap( )
{
super( new HashSet( ) );
}

public HashMap( Map other )


{
super( other );
}

HASH (v2) - 27

Tabela de Dispersão em HashMap

protected Map.Entry makePair( Object key, Object value )


{
return new Pair( key, value );
}

protected Set makeEmptyKeySet( )


{
return new HashSet( );
}

protected Set clonePairSet( Set pairSet )


{
return new HashSet( pairSet );
}

HASH (v2) - 28

Cristina Ribeiro Hash- 14


LEIC-FEUP 2001/2002
Algoritmos e Estruturas de Dados 1

Tabela de Dispersão em HashMap


private static final class Pair implements Map.Entry
{
public Pair( Object k, Object v )
{
key = k;
value = v;
}

public Object getKey( )


{
return key;
}

public Object getValue( )


{
return value;
}

HASH (v2) - 29

Tabela de Dispersão em HashMap

public int hashCode( )


{
return key.hashCode( );
}

public boolean equals( Object other )


{
if( other instanceof Map.Entry )
return getKey( ).equals(
((Map.Entry) other).getKey() );
else
return false;
}

private Object key;


private Object value;
}
}

HASH (v2) - 30

Cristina Ribeiro Hash- 15

Das könnte Ihnen auch gefallen