Você está na página 1de 154

Espalhamento

Sumrio da Apresentao
Espalhamento

A idia inicial de espalhamento


Mtodos de Espalhamento

Implementao das funes Hash


Implementao do Espalhamento

Hash com encadeamento em rea


separada
Hash com encadeamento em rea
primria
Hash usando Endereamento Aberto

Aplicao conta palavras (Java)

Sumrio da Apresentao
Espalhamento
A idia inicial de espalhamento

Exemplo
Mtodos de Espalhamento

Mtodo da Diviso

Mtodo do Meio do Quadrado

Mtodo da Multiplicao
Implementao das funes Hash

Chaves Fundamentais

Chaves de Ponto Flutuante

Chaves de Cadeias de Caracteres

Espalhamento de Objetos

Espalhamento de Containers

Associaes
3

Sumrio da Apresentao
Hash com encadeamento em rea separada

Tabelas Hash Abstratas (s Java)

Encadeamento Separado

Implementao

Construtor e Destrutor (C++)

Construtor e mtodos getLength e purge (Java)

Insero e excluso de itens

Encontro de itens
Hash com encadeamento em rea primria

Tabelas de Espalhamento Encadeadas

Implementao

Construtor e Destrutor (C++)

Construtor e mtodos getLength e purge (Java)

Insero e encontro de itens

Excluso de itens
4

Sumrio da Apresentao
Hash usando Endereamento Aberto
Sondagem linear
Sondagem Quadrtica
Duplo Hashing
Implementao
Construtor e Destrutor
Insero de itens
Encontro de itens
Excluso de itens

Espalhamento

Sumrio do item Espalhamento


A idia inicial de espalhamento
Exemplo
Mtodos de Espalhamento
Mtodo da Diviso
Mtodo do Meio do Quadrado
Mtodo da Multiplicao

A idia inicial de espalhamento


Exemplo:
Deseja-se implementar um container de busca que ser usado
para
armazenar cadeias de caracteres, K
K = {ett; tva, tre, fyra; fem; sex;
aju, atta; nio; tio; elva; tolv}.

Considere-se a definio de uma funo de espalhamento,


ou hash, como mostrado na figura abaixo:
x
h(x)
"ett"
1
"tv"
2
"tre
3
"fyra
4
"fem"
5
"sex
6

x
"sju
"tta
"nio
"tio
"elva
"tolv

h(x)
7
8
9
10
11
12

Espalhamento em memria
Secundria
O Espalhamento em memria secundria
o processo preferencial para a implantao
dos arquivos de acesso direto.

Espalhamento em Memria Secundria


1- Agrupar um determinado nmero de registros em uma
unidade com endereo comum chamada "bucket".
2- Calcular o espao de armazenamento necessrio para o
arquivo. Esse dimensionamento do arquivo depende da
densidade de empacotamento ou fator de carga que a
razo entre o nmero de registros nos arquivos e a
capacidade total dos "buckets".
3- Escolher uma funo "hash" que a transformao a
aplicar chave para obter o endereo do "bucket".
4- Optar por uma tcnica de resoluo do problema de
transbordamento. Ocorre transbordamento ou
"overflow" quando se enderea um registro a um
"bucket" j cheio.

10

Buckets (1)
O arquivo dividido em sees menores denominadas
"buckets", que podem conter um ou mais registros.
A funo "Hash" atribui a cada registro um endereo de
"bucket" ("home address"), onde este pode ser
acomodado.
O tamanho de bucket determinado pelo nmero de
registros que este pode armazenar, ou ainda, pelo
nmero de "slots" que ele contm. Um "slot" uma
unidade de armazenamento que contm espao para
um registro.
Um arquivo com 1000 registros pode ser composto de
1.000 "buckets" de tamanho 1, ou 500 "buckets" de
tamanho 2, etc...
Pode-se relacionar o tamanho do "bucket" a
caractersticas fsicas do meio de armazenamento.
Logo, o tempo de transporte do bucket para a
memria principal proporcional ao tamanho do bucket.
11

Buckets (2)
Ocorre uma coliso quando durante uma incluso de
registros, dois deles tm o mesmo endereo calculado pela
funo hash. Estes registros so chamados sinnimos.
As colises no constituem problemas enquanto no se
atingir a capacidade do "bucket" correspondente. A partir
da, ocorre transbordamento, que consiste no fato de um
registro no poder ser acomodado em "home bucket".
Define-se como "home bucket" aquele que est associado
ao "home address" do registro, que fora calculado pela
funo "hash" aplicada chave do registro.
Aumentando o tamanho dos "buckets" diminui a
probabilidade de transbordamento mas aumenta o tempo
de busca do registro no "bucket". Contudo, o acesso
memria principal mais rpido comparado com o tempo
de busca em memria secundria, uma vez que o bucket
ser transferido para memria principal.
12

Mtodos de Espalhamento

Mtodo do resto da Diviso


Para este caso a funo hash h(x) = x mod M, sendo
M o nmero de endereos disponveis para
armazenamento.
Pode-se implementar um container de busca usando um
array de tamanho n=12. Para inserir o item x, basta
armazena-lo na posio h(x)-1 do array.
Os elementos do conjunto K so chamados de chaves.
usual armazenar estas chaves em um array ou arquivo.
Imediatamente pode-se utilizar esta idia para armazenar
no apenas cadeias de caracteres e sim objetos dos quais
um dos atributos seja uma chave do conjunto K.
A tcnica de "hashing" proporciona uma recuperao de
registros extremamente rpida se comparada com a
recuperao seqencial. O tempo de recuperao em
arquivos sequenciais cresce com o tamanho do arquivo, o
que no ocorre com o "hashing". No projeto de um
arquivo de acesso direto os fatores que necessrio
considerar so os seguintes:
14

Mtodo do Meio Quadrado


O espalhamento pelo meio do quadrado considera que M = 2k, o nmero
de endereos (buckets), um mltiplo de 2. Para palavras de tamanho
W, com w bits as operaes inteiras so feitas mdulo W.
A funo hash de x obtida elevando x ao quadrado mdulo W e
reduzindo este nmero ao domnio {0,1,...,M-1} por meio da
multiplicao por dois elevado a w-k o que zera os w-k bits esquerda.

O cdigo que se segue mostra esta implementao


unsigned int const k = 10; // M==1024
unsigned int const w = bitsizeof(unsigned int);
unsigned int h(unsigned int x) {
return (x * x) >> (w - k);
}

15

Mtodo da Multiplicao
Uma variao do mtodo do meio do quadrado o
mtodo da multiplicao, pelo qual hash de x no
multiplica x por si mesmo e sim por uma constante a
A escolha de a deve ser tal que seja relativamente
primo com W, o que se consegue achando a' tal que aa
= 1 (mod W). Ou seja, a' a inversa de a modulo W.
Vale a propriedade axa'=aa'x=1x.
Para palavras de 32 bits pode-se escolher a =
2.654.435.769 cuja representao binria
10 011 110 001 101 110 111 100 110 111 001.

Sua inversa
O cdigo que se segue mostra esta implementao
unsigned
unsigned
unsigned
unsigned

int
int
int
int

const k = 10; // M==1024


const w = bitsizeof(unsigned int);
const a = 2654435769U;
h(unsigned int x);

16

Implementao das
funes Hash

Sumrio do item
Implementao das funes Hash
Chaves Inteiras
Chaves de Ponto Flutuante
Chaves de Cadeias de
Caracteres
Espalhamento de Objetos
Espalhamento de Containers
Associaes
18

Fundamentos
As chaves dos objetos podem ser de quaisquer tipos de dados
at estruturas como associaes ou containers.
Para um conjunto de chaves, K, e uma constante positiva M,
uma funo hash da forma h: K {0,1,..., M-1}
conveniente implementar a funo h como uma composio
de duas funes f e g. A funo f mapeia chaves em inteiros
f: K Z+
aonde Z+ o conjunto dos inteiros no negativos. A funo g
mapeia inteiros no negativos em {0, 1, ..., M-1}, g: Z + {0,
1, ..., M-1}
Desde que sejam conhecidas as funes f e g, a funo hash
h definida como a composio delas: h = f g
19

Ou seja, o valor de hash de uma chave x dado por g(f(x)).

Implementao das
funes Hash
Implementao C++

Chaves Inteiras
A funo f que mapeia chaves em inteiros para chaves
constitudas de inteiros f(x) = x
Definio da Funo Hash de Inteiros

// pgm08_01.cpp
typedef unsigned int HashValue;
HashValue Hash (char c)
{ return abs (c); }
HashValue Hash (int i)
{ return abs (i); }
21

Chaves de Ponto Flutuante


Todo real no nulo x pode ser expresso da forma x = m * 2 e ,
sendo
A funo f pode ser escrita
Sendo W o maior inteiro que pode ser expresso em uma
palavra do computador x e y colidiro se suas mantissas
diferirem de menos de 1/2W independente do valor dos
expoentes.
Definio da Funo Floating-Point Hash
// pgm08_02.cpp
HashValue Hash (double d) {
if (d == 0)
return 0;
else {
int exponent;
double mantissa = std::frexp (d, &exponent);
return (2 * fabs (mantissa) - 1) * ~0U;
}
}

22

Chaves de Cadeias de Caracteres


Para chaves constitudas de cadeias de caracteres pode-se
concatenar as representaes dos caracteres. Sendo, por
exemplo strings de comprimento 4
, estes
strings podem ser transformados em inteiros pela expresso
Sendo
potncia de 2 pode-se escrever a funo C++:
HashValue Hash (string const& s)
{ return s[0] << 24 | s[1] << 16 | s[2] << 8 | s [3]; }

Para tratar strings de comprimento n pode-se fazer


O inconveniente que no se est fixando limites para f(s).
Pode-se corrigir isto fazendo
aonde
23

Chaves de Cadeias de Caracteres


Sendo W e B potencias de dois o valor calculado
depende apenas dos ltimos W/B caracteres do string.
Para
e
, todos os strings que possuam os
mesmos quatro caracteres colidem.
Considerando f(s) como um polinmio em B, os
coeficientes do polinmio, si, podem ser calculados pela
Regra de Horner, que evita o clculo dos expoentes de
x.
HashValue result = 0;
for (unsigned int i = 0; s [i] != 0; ++i)
result = result * B + s [i];
Como o efeito de considerao de polinmio de base 2
semelhante ao deslocamento (shift) basta concatenar
os resultados parciais
24

Chaves de Cadeias de Caracteres


HashValue result = 0;
for (unsigned int i = 0; s [i] != 0; ++i)
result = result << b ^ s [i];
Pode-se estudar os efeitos de considerao dos caracteres mais
esquerda e mais direita ou ainda utilizar a regra do polinmio com
coeficientes variveis, por exemplo, obtidos de um array s.
Definio da Funo Hash de Character String
//pgm08_03.cpp
unsigned int const shift = 6;
HashValue const mask = ~0U << (bitsizeof (HashValue) - shift);
HashValue Hash (std::string const& s)
{
HashValue result = 0;
for (unsigned int i = 0; s [i] != 0; ++i)
result = (result & mask) ^ (result << shift) ^ s [i];
return result;
25
}

Espalhamento de Objetos
Um template da classe Wrapper usado para envelopar
instncias de tipos de dados C++ construdos em uma
interface abstrata Object. Usando o template as quatro
classes Char, Int, Double, and String so declaradas da
forma:
typedef
typedef
typedef
typedef

Wrapper<char> Char;
Wrapper<int> Int;
Wrapper<double> Double;
Wrapper<string> String;

Como estas classes devem ser concretas devem ter


implementaes de todas as funes membros, inclusive a
funo Hash.
Definio da funo Menbro Hash da Classe Wrapper<T>
//pgm08_04.cpp
template <class T>
HashValue Wrapper<T>::Hash () const
{ return ::Hash (datum); }

26

Espalhamento de Containers
A funo hash f(c) de um container c, com n objetos, o1, o2,
, on definida como

Para obter o hash de um container calcula-se a soma dos


valores hash dos objetos contidos.
A funo Container::Hash usa a funo Accept para fazer
um visitante especial HashingVisitor visitar todos os
objetos do container. Quando visita um objeto chama a
funo Hash do visitado e acumula o resultado.
Definio da funo Membro Hash da Classe Container

27

Espalhamento de Containers
// pgm08_05.cpp
class HashingVisitor : public Visitor {
HashValue value;
public:
HashingVisitor (HashValue _value) : value (_value) {}
void Visit (Object& object)
{ value += object.Hash (); }
HashValue Value () const
{ return value; }
};
HashValue Container::Hash () const {
HashingVisitor visitor (::Hash (typeid (*this).name()));
Accept (visitor);
return visitor.Value ();
}
28

Associaes

J que a funo Accept virtual todas as classes derivadas da


classe Container fornecero as implementaes correspondente
Utilizando o conceito de chave pode-se escrever A = {(k,v):kK,
v V}
A funo hash pode ser expressa como f A(k,v) = fK(k)
Sedo fk a funo hash associada ao conjunto K.
Uma Association possui dois objetos
class Association : public Object, public Ownership {
Object* key;
Object* value;
...};

Para definir a funo hash de uma associao basta chamar a


funo membro hash do objeto para o qual a varivel membro
key aponta
Definio da Funo Hash Member da classe Association

HshValue Association::Hash() const


{ return key->Hash(): }

29

Implementao das
funes Hash
Implementao Java

Mtodo hashCode da classe Int


A funo f que mapeia chaves em inteiros para
chaves constitudas de inteiros f(x) = x
// pgm08_01.java
public class Int extends AbstractObject
{
protected int value;
public int hashCode()
{
return value;
}
// ...
}
31

Mtodo hashCode da classe Dbl


A definio da funo f :
// pgm08_02.java
public class Dbl extends AbstractObject
{
protected double value;
public int hashCode()
{
long bits = Double.doubleToLongBits(value);
return (int)(bits >>> 20);
}
// ...
}
32

Chaves de Cadeias de Caracteres


Para chaves constitudas de cadeias de caracteres pode-se
concatenar as representaes dos caracteres. Sendo, por
exemplo strings de comprimento 4
, este
string pode ser transformado em inteiro pela expresso
Sendo B=27 potncia de 2 pode-se escrever a funo Java:
static int f (String s)
{ return s.charAt(0) << 21 | s.charAt (1) << 14 |
s.charAt (2) << 7 | s.charAt (3); }

Para tratar strings de comprimento n pode-se fazer


O inconveniente que no se est fixando limites para f(s).
Pode-se corrigir isto fazendo
aonde

33

Chaves de Cadeias de Caracteres


Sendo W e B are potencias de dois o valor calculado
depende apenas dos ltimos W/B caracteres do string.
Para
e
, todos os strings que possuam os mesmos
quatro caracteres colidem.
Considerando f(s) como um polinmio em B, os coeficientes
do polinmio, si, podem ser calculados pela Regra de Horner,
que evita o clculo dos expoentes de x.
static int f (String s)
{ int result = 0;
for (int i = 0; i < s.length (); ++i)
result = result * B + s.charAt (i);
return result;
}
Como o efeito de considerao de polinmio de base 2
semelhante ao deslocamento (shift) basta concatenar os
resultados parciais
34

Chaves de Cadeias de Caracteres


static int f (String s)
{ int result = 0;
for (int i = 0; i < s.length () ; ++i)
result = result << b ^ s.charAt (i);
return result;
}
Pode-se estudar os efeitos de considerao dos
caracteres mais esquerda e mais direita ou
ainda utilizar a regra do polinmio com coeficientes
variveis, por exemplo, obtidos de um array s.

35

Mtodo hashCode da classe Str


// pgm08_03.java
public class Str extends AbstractObject
{
protected String value;
private static final int shift = 6;
private static final int mask = ~0 << (32 - shift);
public int hashCode()
{
int result = 0;
for(int i = 0; i < value.length (); ++i)
result = (result & mask) ^ (result << shift) ^
value.charAt (i);
return result;
}
// ...
}

36

Espalhamento de Containers
A funo hash f(c) de um container c, com
n objetos, o1, o2, , on definida como
Para obter o hash de um container
calcula-se a soma dos valores hash dos
objetos contidos.

37

Mtodo hashCode da classe


AbstractContainer
// pgm08_04.java
public abstract class AbstractContainer
extends AbstractObject implements Container {
protected int count;
public int hashCode() {
Visitor visitor = new AbstractVisitor() {
private int value;
public void visit (Object object) {
value += object.hashCode();
}
public int hashCode() {
return value;
}
};
accept (visitor);
return getClass().hashCode() + visitor.hashCode ();
}// ...
}

38

Associaes

J que a funo Accept virtual todas as classes derivadas da


classe Container fornecero as implementaes correspondentes
Utilizando o conceito de chave pode-se escrever
A funo hash pode ser expressa como
Sedo fk a funo hash associada ao conjunto K.
Uma Association possui dois objetos
public class Association
extends AbstractObject
{
protected Comparable key;
protected Object value;
...};

Para definir a funo hash de uma associao basta chamar a


funo membro hash do objeto para o qual a varivel key membr
aponta
39

Mtodo hashCode da classe


Association
// pgm08_05.java
public class Association extends AbstractObject
{
protected Comparable key;
protected Object value;
public int hashCode()
{
return key.hashCode();
}
// ...
}
40

Implementao do Espalhamento

Sumrio do item Implantao do


Espalhamento
Hash com encadeamento em rea separada

Tabelas Hash Abstratas (s Java)

Encadeamento Separado
Hash com encadeamento em rea primria

Tabelas de Espalhamento Encadeadas


Hash usando Endereamento Aberto

Sondagem linear

Sondagem Quadrtica

Duplo Hashing

Implementao

42

Implementao do
Espalhamento
Implementao C++

Tabelas Hash

Definio da Classe HashTable


//pgm08_07.cpp
class HashTable : public virtual SearchableContainer {
protected:
unsigned int length;
public:
HashTable (unsigned int);
virtual unsigned int H (Object const&) const;
};

44

Implementao do Espalhamento
C++
Hash com encadeamento em rea separada

Tabelas Hash
Definio das funes H Member e do Constructor da
Classe HashTable
//pgm08_08.cpp
HashTable::HashTable (unsigned int _length) :
length (_length)
{}
unsigned int HashTable::H (Object const& object) const
{ return object.Hash () % length; }

O construtor de HashTable recebe um simples argumento


e inicializa a varivel membro de maneira adequada. A
funo membro corresponde composio h = g f. A
funo membro H recebe como argumento uma referencia
constante a um objeto e retorna o resultado Hash modulo
46
length.

Encadeamento Separado
Tabela Hash usando Encadeamento Separado

47

Definio da Classe
ChainedHashTable
// pgm08_09.cpp
class ChainedHashTable : public HashTable
{
Array<LinkedList<Object*> > array;
public:
ChainedHashTable (unsigned int);
// ...
};

48

Definio das funes Purge


Member, Constructor e Destructor da
Classe ChainedHashTable (1)
// pgm08_10.cpp
ChainedHashTable::ChainedHashTable (unsigned int
_length) :
HashTable (_length),
array (_length)
{}

49

Definio das funes Purge


Member, Constructor e Destructor
da Classe ChainedHashTable (2)
// pgm08_10.cpp (Continuao)
void ChainedHashTable::Purge()
{
for (unsigned int i = 0; i < length; ++i) {
if(IsOwner ()) {
ListElement<Object*> const* ptr;
for( ptr = array[i].Head (); ptr != 0;
ptr = ptr->Next() )
delete ptr->Datum ();
}
array[i].Purge();
}
count = 0;
}
ChainedHashTable::~ChainedHashTable ()
{ Purge (); }

50

Definio das Funes Insert e


Withdraw Member da Classe
ChainedHashTable
// pgm08_11.cpp
void ChainedHashTable::Insert (Object& object)
{
array [H (object)].Append (&object);
++count;
}
void ChainedHashTable::Withdraw (Object& object)
{
array [H (object)].Extract (&object);
--count;
}

51

Definio da Funo Find Member da


Classe ChainedHashTable
// pgm08_12.cpp
Object& ChainedHashTable::Find (Object const& object) const
{
ListElement<Object*> const* ptr;
for(ptr = array [H (object)].Head (); ptr != 0;
ptr = ptr->Next())
{
if(object == *ptr->Datum ())
return *ptr->Datum ();
}
return NullObject::Instance ();
}

52

Implementao do Espalhamento
C++
Hash com encadeamento em rea primria

Hash com encadeamento em rea


primria
Quando usado Hash com encadeamento em rea primria
o transbordamento tratado por listas encadeadas
iniciadas nos home addresses.

54

Definio da Classe
ChainedScatterTable
// pgm08_13.cpp
class ChainedScatterTable : public HashTable
{
class Entry {
public:
enum { null = ~0U };
Object* object;
unsigned int next;
Entry ();
};
Array<Entry> array;
public:
ChainedScatterTable (unsigned int);
// ...
};

55

Definio das Funes Purge Member,


Constructor e Destructor da Classe
ChainedScatterTable e Constructor da Classe
ChainedScatterTable::Entry (1)

//pgm08_14.cpp

ChainedScatterTable::Entry::Entry () :
object (0),
next (null)
{}
ChainedScatterTable::ChainedScatterTable (unsigned int
_length) :
HashTable (_length),
array (_length)
{}

56

Definio das Funes Purge Member,


Constructor e Destructor da Classe
ChainedScatterTable e Constructor da Classe
ChainedScatterTable::Entry (2)
// pgm08_14.cpp (Continuao)
void ChainedScatterTable::Purge ()
{
for(unsigned int i = 0; i < length; ++i) {
if(array [i].object != 0)
{
if(IsOwner ())
delete array [i].object;
array [i] = Entry ();
}
}
count = 0;
}
ChainedScatterTable::~ChainedScatterTable ()
{ Purge (); }

57

Definio das Funes Insert e Find


Member da Classe
ChainedScatterTable (1)

// pgm08_15.cpp

void ChainedScatterTable::Insert (Object& object) {


if (count == length)
throw domain_error ("scatter table is full");
unsigned int probe = H(object);
if(array[probe].object != 0) {
while(array[probe].next != Entry::null)
probe = array [probe].next;
unsigned int const tail = probe;
probe = (probe + 1) % length;
while(array[probe].object != 0)
probe = (probe + 1) % length;
array[tail].next = probe;
}
58

Definio das Funes Insert e Find


Member da Classe
ChainedScatterTable (2)
// pgm08_15.cpp (Continuao)
array[probe].object = &object;
array[probe].next = Entry::null;
++count;
}
Object& ChainedScatterTable::Find(Object const&
object)const
{
for(unsigned int probe = H (object);
probe != Entry::null; probe = array [probe].next) {
if(object == *array[probe].object)
return *array[probe].object;
}
return NullObject::Instance();
}
59

Definio da Funo Withdraw


Member da Classe
ChainedScatterTable
(1)
// pgm08_16.cpp
void ChainedScatterTable::Withdraw (Object& object)
{
if(count == 0)
throw domain_error ("scatter table is empty");
unsigned int i = H (object);
while(i != Entry::null && array[i].object != &object)
i = array[i].next;
if(i == Entry::null)
throw invalid_argument ("object not found");

60

Definio da Funo Withdraw


Member da Classe
ChainedScatterTable (2)
// pgm08_16.cpp (Continuao)
for(;;)
{
unsigned int j;
for(j = array[i].next; j != Entry::null; j =
array[j].next)
{
unsigned int const h = H (*array[j].object);
bool contained = false;
for(unsigned int k = array[i].next; k !=
array[j].next && !contained; k = array[k].next) {
if(k == h)
contained = true;
}
if(!contained)
break;
}
61

Definio da Funo Withdraw


Member da Classe
ChainedScatterTable (3)
// pgm08_16.cpp (Continuao)
if(j == Entry::null)
break;
array[i].object = array[j].object;
i = j;
}
array[i].object = 0;
array[i].next = Entry::null;
for(unsigned int j = (i + length - 1U) % length; j != i;
j = (j + length - 1U) % length) {
if(array[j].next == i) {
array[j].next = Entry::null;
break;
}
}
--count;
}

62

Implementao do Espalhamento
C++
Hash usando Endereamento Aberto

Tabelas de Espalhamento usando


Endereamento Aberto (1)
A seqncia de sondagem uma seqncia de funes
h0 , h1 ,..., hM 1

aonde hi uma funo hash hi: K {0,1,...,M-1}


A insero de um item x na tabela de espalhamento feita
examinando as posies h0(x), h1(x),..., at encontrar uma clula vazia.

A busca de um item na tabela segue a mesma


seqncia.
As seqncias de sondagem mais comuns so do tipo

para i = 0,1,,M-1

hi ( x) (h(c(i)
x) crepresenta
(i )) mod M i a estratgia de resoluo de
A funo
transbordamentos.

64

Tabelas de Espalhamento usando


Endereamento Aberto (2)
Sondagem Linear
Na sondagem linear a funo c(i) linear em i.

c(i ) (i )
Ou, da maneira mais comumc (i )

(i )

e M devem ser primos relativos.


Para i = 0,1,,M-1

hi (h( x) i ) mod M

65

Tabelas de Espalhamento usando


Endereamento Aberto (3)
Tabela de Espalhamento usando Endereamento Aberto e
Sondagem Linear

66

Tabelas de Espalhamento usando


Endereamento Aberto (4)
Sondagem Quadrtica

c(i ) i 2 i
Na sondagem linear a funo c(i) quadrtica em i.
Ou, da maneira mais comum

c(i ) i 2

67

Tabelas de Espalhamento usando


Endereamento Aberto (5)
Duplo Hashing
Pode-se gerar uma seqncia de sondagem por meio
da tcnica de duplo hashing que usa duas funes h e
h . h : K 0,1,..., M 1
h ' : K 1,2,..., M 1
A seqncia de sondagem
obtida da forma
'

hi ( x) (h( x) ih ( x)) mod M

68

Definio da Classe OpenScatterTable


// pgm08_17.cpp
class OpenScatterTable : public HashTable {
class Entry {
public:
enum State { empty, occupied, deleted };
State state;
Object* object;
Entry ();
};
Array<Entry> array;
unsigned int C (unsigned int) const;
unsigned int FindMatch (Object const&) const;
unsigned int FindInstance (Object const&) const;
unsigned int FindUnoccupied (Object const&) const;
public:
OpenScatterTable (unsigned int);
// ...
};
69

Construtores e Destrutores
O construtor default para a classe
OpenScatterTable::Entry faz com que uma entrada no
ocupada tenha o ponteiro para seu objeto zerada e o
estado default de todas as entradas empty. Este
construtor default inicializa as duas variveis membro
de maneira adequada.

70

Definio do Constructor e Destructor da


Classe OpenScatterTable e do Constructor
// pgm08_18.cpp
da
Classe
OpenScatterTable::Entry
OpenScatterTable::Entry::Entry() : state (empty), object

(0) {}
OpenScatterTable::OpenScatterTable (unsigned int _length) :
HashTable (_length), array (_length) {}
void OpenScatterTable::Purge() {
for (unsigned int i = 0; i < length; ++i) {
if (array [i].state == Entry::occupied) {
if (IsOwner ())
delete array [i].object;
array [i] = Entry ();
}
}
count = 0;
}
OpenScatterTable::~OpenScatterTable ()
{ Purge (); }

71

Definio das Funes C,


FindUnoccupied e Insert Member da
Classe OpenScatterTable (1)
// pgm08_19.cpp
unsigned int OpenScatterTable::C (unsigned int i) const
{ return i; }
unsigned int OpenScatterTable::FindUnoccupied(Object
const& object) const
{
unsigned int const hash = H (object);
for (unsigned int i = 0; i < count + 1; ++i)
{
unsigned int const probe = (hash + C (i)) % length;
if (array [probe].state != Entry::occupied)
return probe;
}
return length;
}
72

Definio das Funes C,


FindUnoccupied e Insert Member da
Classe OpenScatterTable (2)
// pgm08_19.cpp
void OpenScatterTable::Insert(Object& object) {
if (count == length)
throw domain_error ("scatter table is full");
unsigned int const offset = FindUnoccupied
(object);
array [offset].state = Entry::occupied;
array [offset].object = &object;
++count;
}

A funo c define a seqncia de sondagem. Para


sondagem linear a funo c a funo identidade.
A funo membro FindUnoccupied encontrar uma posio
desocupada. A rotina FindUnoccupied sonda o array de
acorde com a seqncia de sondagem determinada pela
73
funo c.

Definio das Funes FindMatch e


Find Member da Classe
OpenScatterTable (1)
// pgm08_20.cpp
unsigned int OpenScatterTable::FindMatch(Object const&
object) const
{
unsigned int const hash = H (object);
for(unsigned int i = 0; i < length; ++i)
{
unsigned int const probe = (hash + C (i)) % length;
if(array[probe].state == Entry::empty)
break;
if(array[probe].state == Entry::occupied
&& object == *array[probe].object)
return probe;
}
return length;
}
74

Definio das Funes FindMatch e


Find Member da Classe
OpenScatterTable (2)
// pgm08_20.cpp (Continuao)
Object& OpenScatterTable::Find (Object const& object)
const
{
unsigned int const offset = FindMatch (object);
if (offset < length)
return *array [offset].object;
else
return NullObject::Instance ();
}

75

Definio da Funo Withdraw


Member da Classe OpenScatterTable
// pgm08_21.cpp
void OpenScatterTable::Withdraw (Object& object)
{
if (count == 0)
throw domain_error ("scatter table is empty");
unsigned int const offset = FindInstance (object);
if (offset == length)
throw invalid_argument ("object not found");
array [offset].state = Entry::deleted;
array [offset].object = 0;
--count;
}

76

OpenScatterTable Class Alternate


Withdraw Member Function (1)
// pgm08_22.cpp
void OpenScatterTable::Withdraw(Object& object)
{
if(count == 0)
throw domain_error ("scatter table is empty");
unsigned int i = FindInstance (object);
if(i == length)
throw invalid_argument ("object not found");
for(;;) {
unsigned int j;
for(j = (i + 1) % length; array[j].state ==
Entry::occupied; j = (j + 1) % length)
{
unsigned int const h = H (*array [j].object);
if( (h <= i && i < j) || (i < j && j < h) ||
(j < h && h <= i) )
break;
77
}

OpenScatterTable Class Alternate


Withdraw Member Function (2)
// pgm08_22.cpp (Continuao)
if(array[j].state == Entry::empty)
break;
array[i] = array[j];
i = j;
}
array[i].state = Entry::empty;
array[i].object = 0;
--count;
}

78

Implementao Java

Implementao do Espalhamento
Java
Hash com encadeamento em rea separada

Tabelas Hash

Interface HashTable
// pgm08_06.java
public interface HashTable extends SearchableContainer
{
double getLoadFactor();
}

81

Mtodos AbstractHashTable
// pgm08_07.java
public abstract class AbstractHashTable
extends AbstractSearchableContainer implements HashTable
{
public abstract int getLength();
protected final int f(Object object) {
return object.hashCode();
}
protected final int g(int x) {
return Math.abs(x) % getLength();
}
protected final int h(Object object) {
return g( f(object) );
}
// ...
}

82

Encadeamento Separado
Tabela Hash usando Encadeamento Separado

83

Campos ChainedHashTable
// pgm08_08.java
public class ChainedHashTable extends AbstractHashTable
{
protected LinkedList[] array;
// ...
}

84

Mtodos constructor, getLength e


purge da classe ChainedHashTable
// pgm08_09.java
public class ChainedHashTable extends AbstractHashTable {
protected LinkedList[] array;
public ChainedHashTable(int length) {
array = new LinkedList [length];
for(int i = 0; i < length; ++i)
array[i] = new LinkedList();
}
public int getLength() {
return array.length;
}
public void purge() {
for(int i = 0; i < getLength(); ++i)
array[i].purge();
count = 0;
}
// ...
85
}

Mtodos insert e withdraw da classe


ChainedHashTable
// pgm08_10.java
public class ChainedHashTable extends AbstractHashTable
{
protected LinkedList[] array;
public void insert(Comparable object)
{
array[h (object)].append(object);
++count;
}
public void withdraw(Comparable object)
{
array[h (object)].extract(object);
--count;
}
// ...
}

86

Mtodo find da classe


ChainedHashTable
// pgm08_11.java
public class ChainedHashTable extends AbstractHashTable
{
protected LinkedList[] array;
public Comparable find(Comparable object)
{
for(LinkedList.Element ptr = array[h(object)].getHead();
ptr != null; ptr = ptr.getNext())
{
Comparable datum = (Comparable) ptr.getDatum();
if(object.isEQ (datum))
return datum;
}
return null;
}
// ...
}

87

Mtodo getLoadFactor da classe


AbstractHashTable
// pgm08_12.java
public abstract class AbstractHashTable
extends AbstractSearchableContainer implements HashTable
{
public abstract int getLength();
public final double getLoadFactor()
{
return (double) getCount() / getLength();
}
// ...
}
88

Implementao do Espalhamento
Java
Hash com encadeamento em rea primria

Hash com encadeamento em


rea primria
Quando usado
Hash com
encadeamento
em rea primria
o
transbordamento
tratado por
listas encadeadas
iniciadas nos
home
addresses.
90

Classe ChainedScatterTable.Entry e
campos ChainedScatterTable
// pgm08_13.java
public class ChainedScatterTable extends AbstractHashTable
{
protected Entry[] array;
static final int nil = -1;
protected static final class Entry {
Comparable object;
int next = nil;
void purge() {
object = null;
next = nil;
}
}
// ...
}
91

Mtodos constructor, getLength e


purge da classe
ChainedScatterTable (1)
// pgm08_14.java
public class ChainedScatterTable
extends AbstractHashTable
{
protected Entry[] array;
public ChainedScatterTable(int length)
{
array = new Entry [length];
for(int i = 0; i < length; ++i)
array [i] = new Entry ();
}
92

Mtodos constructor, getLength e


purge da classe
ChainedScatterTable (2)
// pgm08_14.java (Continuao)
public int getLength()
{
return array.length;
}
public void purge()
{
for(int i = 0; i < getLength (); ++i)
array [i].purge();
count = 0;
}
// ...
}
93

Mtodos insert e find da classe


ChainedScatterTable (1)
// pgm08_15.java
public class ChainedScatterTable extends AbstractHashTable
{
protected Entry[] array;
public void insert(Comparable object) {
if(count == getLength ())
throw new ContainerFullException();
int probe = h(object);
if(array[probe].object != null) {
while(array[probe].next != nil)
probe = array [probe].next;
int tail = probe;
probe = (probe + 1) % getLength();
while(array[probe].object != null)
probe = (probe + 1) % getLength();
array[tail].next = probe;
94
}

Mtodos insert e find da classe


ChainedScatterTable (2)
// pgm08_15.java (Continuao)
array[probe].object = object;
array[probe].next = nil;
++count;
}
public Comparable find(Comparable object) {
for(int probe = h(object); probe != nil; probe =
array [probe].next) {
if( object.isEQ(array[probe].object) )
return array[probe].object;
}
return null;
}
// ...
}

95

Mtodo withdraw da classe


ChainedScatterTable (1)
// pgm08_16.java
public class ChainedScatterTable extends AbstractHashTable
{
protected Entry[] array;
public void withdraw(Comparable object)
{
if(count == 0)
throw new ContainerEmptyException();
int i = h(object);
while(i != nil && object != array[i].object)
i = array[i].next;
if(i == nil)
throw new IllegalArgumentException("obj not found");
96

Mtodo withdraw da classe


ChainedScatterTable (2)
// pgm08_16.java (Continuao)
for(;;)
{
int j = array[i].next;
while(j != nil)
{
int h = h(array[j].object);
boolean contained = false;
for(int k = array[i].next; k != array[j].next &&
!contained; k = array[k].next)
{
if(k == h)
contained = true;
}
97

Mtodo withdraw da classe


ChainedScatterTable (3)
// pgm08_16.java (Continuao)
if(!contained)
break;
j = array[j].next;
}
if(j == nil)
break;
array[i].object = array[j].object;
i = j;
}

98

Mtodo withdraw da classe


ChainedScatterTable (3)
// pgm08_16.java (Continuao)
array[i].object = null;
array[i].next = nil;
for(int j = (i + getLength () - 1) % getLength ();
j != i; j = (j + getLength () - 1) % getLength ())
{
if(array[j].next == i)
{
array[j].next = nil;
break;
}
}
--count;
}
// ...
}

99

Implementao do Espalhamento
Java
Hash usando Endereamento Aberto

Hash usando endereamento


aberto

Tabela de Espalhamento usando Endereamento Aberto e Sondagem

101

OpenScatterTable.Entry e campos
OpenScatterTable fields
// pgm08_17.java
public class OpenScatterTable extends AbstractHashTable {
protected Entry[] array;
static final int empty = 0;
static final int occupied = 1;
static final int deleted = 2;
protected static final class Entry {
int state = empty;
Comparable object;
void purge() {
state = empty;
object = null;
}
}
// ...
102
}

Mtodos constructor, getLength e


purge da classe OpenScatterTable
// pgm08_18.java
public class OpenScatterTable extends AbstractHashTable {
protected Entry[] array;
public OpenScatterTable(int length) {
array = new Entry [length];
for(int i = 0; i < length; ++i)
array[i] = new Entry();
}
public int getLength() {
return array.length;
}
public void purge() {
for (int i = 0; i < getLength (); ++i)
array[i].purge();
count = 0;
}
// ...
103
}

Mtodos c, findUnoccupied e insert


da classe OpenScatterTable (1)
// pgm08_19.java
public class OpenScatterTable extends AbstractHashTable
{
protected Entry[] array;
protected static int c(int i) {
return i;
}
protected int findUnoccupied(Object object) {
int hash = h(object);
for(int i = 0; i < count + 1; ++i) {
int probe = (hash + c (i)) % getLength();
if(array [probe].state != occupied)
return probe;
}
throw new ContainerFullException();
}
104

Mtodos c, findUnoccupied e insert


da classe OpenScatterTable (2)
// pgm08_19.java (Continuao)
public void insert(Comparable object)
{
if(count == getLength ())
throw new ContainerFullException();
int offset = findUnoccupied(object);
array[offset].state = occupied;
array[offset].object = object;
++count;
}
// ...
}
105

Mtodos findMatch e find da classe


OpenScatterTable (1)
//pgm08_20.java
public class OpenScatterTable extends AbstractHashTable
{
protected Entry[] array;
protected int findMatch(Comparable object) {
int hash = h(object);
for(int i = 0; i < getLength (); ++i) {
int probe = (hash + c (i)) % getLength();
if(array[probe].state == empty)
break;
if(array[probe].state == occupied &&
object.isEQ(array[probe].object)) {
return probe;
}
}
return -1;
}

106

Mtodos findMatch e find da classe


OpenScatterTable (2)
// pgm08_20.java (Continuao)
public Comparable find(Comparable object)
{
int offset = findMatch(object);
if(offset >= 0)
return array[offset].object;
else
return null;
}
// ...
}

107

Mtodo withdraw da classe


OpenScatterTable
//pgm08_21.java
public class OpenScatterTable extends AbstractHashTable {
protected Entry[] array;
public void withdraw(Comparable object) {
if(count == 0)
throw new ContainerEmptyException();
int offset = findInstance(object);
if(offset < 0)
throw new IllegalArgumentException("object not
found");
array[offset].state = deleted;
array[offset].object = null;
--count;
}
// ...
108
}

Mtodo OpenScatterTableV2
withdraw (1)
// pgm08_22.java
public class OpenScatterTableV2 extends OpenScatterTable {
public void withdraw(Comparable object) {
if(count == 0)
throw new ContainerEmptyException();
int i = findInstance(object);
if(i < 0)
throw new IllegalArgumentException("object not found");
for(;;) {
int j = (i + 1) % getLength();
while(array[j].state == occupied) {
int h = h(array[j].object);
if((h <= i && i < j) || (i < j && j < h) ||
(j < h && h <= i))
break;
j = (j + 1) % getLength();
109
}

Mtodo OpenScatterTableV2
withdraw (2)
// pgm08_22.java (Continuao)
if(array[j].state == empty)
break;
array[i].state = array[j].state;
array[i].object = array[j].object;
i = j;
}
array[i].state = empty;
array[i].object = null;
--count;
}
// ...
}

110

Aplicao
Java

Aplicao Hash/scatter table


contador de palavras (1)
// pgm08_23.java
public class Algorithms
{
private static final class Counter extends Int
{
Counter(int value)
{
super(value);
}
void increment()
{
++value;
}
}
112

Aplicao Hash/scatter table


contador de palavras (2)
// pgm08_23.java (Continuao)
public static void wordCounter(Reader in, PrintWriter out)
throws IOException
{
HashTable table = new ChainedHashTable(1031);
StreamTokenizer tin = new StreamTokenizer(in);
while(tin.nextToken() != StreamTokenizer.TT_EOF)
{
String word = tin.sval;
Object obj = table.find(new
Association(new Str (word)));
if(obj == null)
table.insert(new Association(new Str(word),
new Counter(1)));
113

Aplicao Hash/scatter table


contador de palavras (3)
// pgm08_23.java (Continuao)
else
{
Association assoc = (Association) obj;
Counter counter = (Counter) assoc.getValue();
counter.increment();
}
}
out.println(table);
}
}

114

Aplicaes
Aplicao da Hash/Scatter Table--Contando Palavras
Uma aplicao de espalhamento a contagem do
nmero de ocorrncias distintas de cada palavra
contida em um arquivo texto.
AplicaesAplicao da Hash/Scatter Table--Contando
Palavras (1)
//pgm08_23.cpp
class Counter : public Int {
public:
Counter (int i) : Int(i) {}
void operator ++ ()
{ ++datum; }
};

115

Aplicaes
AplicaesAplicao da Hash/Scatter Table--Contando Palavras (2)
// pgm08_23.cpp (Continuao)
void CountWords(HashTable& table) {
std::string word;
while (cin >> word, !cin.eof ()) {
Object& obj = table.Find(Association (*new String (word)));
if(obj.IsNull ())
table.Insert( *new Association(*new String(word),
*new Counter (1)) );
else {
Association& assoc = dynamic_cast<Association&> (obj);
Counter& i = dynamic_cast<Counter&> (assoc.Value ());
++i;
}
}
cout << table << endl;
}

116

Implementao Java

Hierarquia de Classes

118

Tabelas Hash

Interface HashTable
// pgm08_06.java
public interface HashTable extends SearchableContainer
{
double getLoadFactor();
}

119

Aplicao Conta Palavras em Java

Hash com encadeamento em rea separada

Mtodos AbstractHashTable
// pgm08_07.java
public abstract class AbstractHashTable
extends AbstractSearchableContainer implements HashTable
{
public abstract int getLength();
protected final int f(Object object) {
return object.hashCode();
}
protected final int g(int x) {
return Math.abs(x) % getLength();
}
protected final int h(Object object) {
return g( f(object) );
}
// ...
}

121

Encadeamento Separado
Tabela Hash usando Encadeamento Separado

122

Campos ChainedHashTable
// pgm08_08.java
public class ChainedHashTable extends AbstractHashTable
{
protected LinkedList[] array;
// ...
}

123

Mtodos constructor, getLength e


purge da classe ChainedHashTable
// pgm08_09.java
public class ChainedHashTable extends AbstractHashTable {
protected LinkedList[] array;
public ChainedHashTable(int length) {
array = new LinkedList [length];
for(int i = 0; i < length; ++i)
array[i] = new LinkedList();
}
public int getLength() {
return array.length;
}
public void purge() {
for(int i = 0; i < getLength(); ++i)
array[i].purge();
count = 0;
}
// ...
124
}

Mtodos insert e withdraw da classe


ChainedHashTable
// pgm08_10.java
public class ChainedHashTable extends AbstractHashTable
{
protected LinkedList[] array;
public void insert(Comparable object)
{
array[h (object)].append(object);
++count;
}
public void withdraw(Comparable object)
{
array[h (object)].extract(object);
--count;
}
// ...
}

125

Mtodo find da classe


ChainedHashTable
// pgm08_11.java
public class ChainedHashTable extends AbstractHashTable
{
protected LinkedList[] array;
public Comparable find(Comparable object)
{
for(LinkedList.Element ptr = array[h(object)].getHead();
ptr != null; ptr = ptr.getNext())
{
Comparable datum = (Comparable) ptr.getDatum();
if(object.isEQ (datum))
return datum;
}
return null;
}
// ...
}

126

Mtodo getLoadFactor da classe


AbstractHashTable
// pgm08_12.java
public abstract class AbstractHashTable
extends AbstractSearchableContainer implements HashTable
{
public abstract int getLength();
public final double getLoadFactor()
{
return (double) getCount() / getLength();
}
// ...
}
127

Aplicao Conta Palavras em Java

Hash com encadeamento em


rea primria

Hash com encadeamento em rea


primria
Quando usado Hash com encadeamento em rea
primria o transbordamento tratado por listas
encadeadas iniciadas nos home addresses.

129

Classe ChainedScatterTable.Entry e
campos ChainedScatterTable
// pgm08_13.java
public class ChainedScatterTable extends AbstractHashTable
{
protected Entry[] array;
static final int nil = -1;
protected static final class Entry {
Comparable object;
int next = nil;
void purge() {
object = null;
next = nil;
}
}
// ...
}
130

Mtodos constructor, getLength e


purge da classe
ChainedScatterTable (1)
// pgm08_14.java
public class ChainedScatterTable
extends AbstractHashTable
{
protected Entry[] array;
public ChainedScatterTable(int length)
{
array = new Entry [length];
for(int i = 0; i < length; ++i)
array [i] = new Entry ();
}
131

Mtodos constructor, getLength e


purge da classe
ChainedScatterTable (2)
// pgm08_14.java (Continuao)
public int getLength()
{
return array.length;
}
public void purge()
{
for(int i = 0; i < getLength (); ++i)
array [i].purge();
count = 0;
}
// ...
}
132

Mtodos insert e find da classe


ChainedScatterTable (1)
// pgm08_15.java
public class ChainedScatterTable extends AbstractHashTable
{
protected Entry[] array;
public void insert(Comparable object) {
if(count == getLength ())
throw new ContainerFullException();
int probe = h(object);
if(array[probe].object != null) {
while(array[probe].next != nil)
probe = array [probe].next;
int tail = probe;
probe = (probe + 1) % getLength();
while(array[probe].object != null)
probe = (probe + 1) % getLength();
array[tail].next = probe;
133
}

Mtodos insert e find da classe


ChainedScatterTable (2)
// pgm08_15.java (Continuao)
array[probe].object = object;
array[probe].next = nil;
++count;
}
public Comparable find(Comparable object) {
for(int probe = h(object); probe != nil; probe =
array [probe].next) {
if( object.isEQ(array[probe].object) )
return array[probe].object;
}
return null;
}
// ...
}

134

Mtodo withdraw da classe


ChainedScatterTable (1)
// pgm08_16.java
public class ChainedScatterTable extends AbstractHashTable
{
protected Entry[] array;
public void withdraw(Comparable object)
{
if(count == 0)
throw new ContainerEmptyException();
int i = h(object);
while(i != nil && object != array[i].object)
i = array[i].next;
if(i == nil)
throw new IllegalArgumentException("obj not found");
135

Mtodo withdraw da classe


ChainedScatterTable (2)
// pgm08_16.java (Continuao)
for(;;)
{
int j = array[i].next;
while(j != nil)
{
int h = h(array[j].object);
boolean contained = false;
for(int k = array[i].next; k != array[j].next &&
!contained; k = array[k].next)
{
if(k == h)
contained = true;
}
136

Mtodo withdraw da classe


ChainedScatterTable (3)
// pgm08_16.java (Continuao)
if(!contained)
break;
j = array[j].next;
}
if(j == nil)
break;
array[i].object = array[j].object;
i = j;
}

137

Mtodo withdraw da classe


ChainedScatterTable (3)
// pgm08_16.java (Continuao)
array[i].object = null;
array[i].next = nil;
for(int j = (i + getLength () - 1) % getLength ();
j != i; j = (j + getLength () - 1) % getLength ())
{
if(array[j].next == i)
{
array[j].next = nil;
break;
}
}
--count;
}
// ...
}

138

Aplicao Conta Palavras em Java

Hash usando Endereamento


Aberto

Tabelas de Espalhamento usando


Endereamento Aberto (1)
A seqncia de sondagem uma seqncia de funes
h0 , h1 ,..., hM 1

aonde hi uma funo hash hi: K {0,1,...,M-1}


A insero de um item x na tabela de espalhamento feita
examinando as posies h0(x), h1(x),..., at encontrar uma clula vazia.

A busca de um item na tabela segue a mesma


seqncia.
As seqncias de sondagem mais comuns so do tipo

para i = 0,1,,M-1

hi ( x) (h(c(i)
x) crepresenta
(i )) mod M i a estratgia de resoluo de
A funo
transbordamentos.

140

Tabelas de Espalhamento usando


Endereamento Aberto (2)
Sondagem Linear
Na sondagem linear a funo c(i) linear em i.

c(i ) (i )
Ou, da maneira mais comumc (i )

(i )

e M devem ser primos relativos.


Para i = 0,1,,M-1

hi (h( x) i ) mod M

141

Tabelas de Espalhamento usando


Endereamento Aberto (3)

Tabela de
Espalhamento usando
Endereamento Aberto
e Sondagem Linear

142

OpenScatterTable.Entry e campos
OpenScatterTable fields
// pgm08_17.java
public class OpenScatterTable extends AbstractHashTable {
protected Entry[] array;
static final int empty = 0;
static final int occupied = 1;
static final int deleted = 2;
protected static final class Entry {
int state = empty;
Comparable object;
void purge() {
state = empty;
object = null;
}
}
// ...
143
}

Mtodos constructor, getLength e


purge da classe OpenScatterTable
// pgm08_18.java
public class OpenScatterTable extends AbstractHashTable {
protected Entry[] array;
public OpenScatterTable(int length) {
array = new Entry [length];
for(int i = 0; i < length; ++i)
array[i] = new Entry();
}
public int getLength() {
return array.length;
}
public void purge() {
for (int i = 0; i < getLength (); ++i)
array[i].purge();
count = 0;
}
// ...
144
}

Mtodos c, findUnoccupied e insert


da classe OpenScatterTable (1)
// pgm08_19.java
public class OpenScatterTable extends AbstractHashTable
{
protected Entry[] array;
protected static int c(int i) {
return i;
}
protected int findUnoccupied(Object object) {
int hash = h(object);
for(int i = 0; i < count + 1; ++i) {
int probe = (hash + c (i)) % getLength();
if(array [probe].state != occupied)
return probe;
}
throw new ContainerFullException();
}
145

Mtodos c, findUnoccupied e insert


da classe OpenScatterTable (2)
// pgm08_19.java (Continuao)
public void insert(Comparable object)
{
if(count == getLength ())
throw new ContainerFullException();
int offset = findUnoccupied(object);
array[offset].state = occupied;
array[offset].object = object;
++count;
}
// ...
}
146

Mtodos findMatch e find da classe


OpenScatterTable (1)
//pgm08_20.java
public class OpenScatterTable extends AbstractHashTable
{
protected Entry[] array;
protected int findMatch(Comparable object) {
int hash = h(object);
for(int i = 0; i < getLength (); ++i) {
int probe = (hash + c (i)) % getLength();
if(array[probe].state == empty)
break;
if(array[probe].state == occupied &&
object.isEQ(array[probe].object)) {
return probe;
}
}
return -1;
}

147

Mtodos findMatch e find da classe


OpenScatterTable (2)
// pgm08_20.java (Continuao)
public Comparable find(Comparable object)
{
int offset = findMatch(object);
if(offset >= 0)
return array[offset].object;
else
return null;
}
// ...
}

148

Mtodo withdraw da classe


OpenScatterTable
//pgm08_21.java
public class OpenScatterTable extends AbstractHashTable {
protected Entry[] array;
public void withdraw(Comparable object) {
if(count == 0)
throw new ContainerEmptyException();
int offset = findInstance(object);
if(offset < 0)
throw new IllegalArgumentException("object not
found");
array[offset].state = deleted;
array[offset].object = null;
--count;
}
// ...
149
}

Mtodo OpenScatterTableV2
withdraw (1)
// pgm08_22.java
public class OpenScatterTableV2 extends OpenScatterTable {
public void withdraw(Comparable object) {
if(count == 0)
throw new ContainerEmptyException();
int i = findInstance(object);
if(i < 0)
throw new IllegalArgumentException("object not found");
for(;;) {
int j = (i + 1) % getLength();
while(array[j].state == occupied) {
int h = h(array[j].object);
if((h <= i && i < j) || (i < j && j < h) ||
(j < h && h <= i))
break;
j = (j + 1) % getLength();
150
}

Mtodo OpenScatterTableV2
withdraw (2)
// pgm08_22.java (Continuao)
if(array[j].state == empty)
break;
array[i].state = array[j].state;
array[i].object = array[j].object;
i = j;
}
array[i].state = empty;
array[i].object = null;
--count;
}
// ...
}

151

Aplicao Hash/scatter table


contador de palavras (1)
// pgm08_23.java
public class Algorithms
{
private static final class Counter extends Int
{
Counter(int value)
{
super(value);
}
void increment()
{
++value;
}
}
152

Aplicao Hash/scatter table


contador de palavras (2)
// pgm08_23.java (Continuao)
public static void wordCounter(Reader in, PrintWriter out)
throws IOException
{
HashTable table = new ChainedHashTable(1031);
StreamTokenizer tin = new StreamTokenizer(in);
while(tin.nextToken() != StreamTokenizer.TT_EOF)
{
String word = tin.sval;
Object obj = table.find(new
Association(new Str (word)));
if(obj == null)
table.insert(new Association(new Str(word),
new Counter(1)));
153

Aplicao Hash/scatter table


contador de palavras (3)
// pgm08_23.java (Continuao)
else
{
Association assoc = (Association) obj;
Counter counter = (Counter) assoc.getValue();
counter.increment();
}
}
out.println(table);
}
}

154