Espalhamento

Propaganda
Espalhamento
Sumário da Apresentação
Espalhamento


A idéia inicial de espalhamento
Métodos de Espalhamento
Implementação das funções Hash
Implementação do Espalhamento



Hash com encadeamento em área
separada
Hash com encadeamento em área
primária
Hash usando Endereçamento Aberto
Aplicação conta palavras (Java)
2
Sumário da Apresentação
Espalhamento
A idéia inicial de espalhamento

Exemplo
Métodos de Espalhamento

Método da Divisão

Método do Meio do Quadrado

Método da Multiplicação
Implementação das funções Hash

Chaves Fundamentais

Chaves de Ponto Flutuante

Chaves de Cadeias de Caracteres

Espalhamento de Objetos

Espalhamento de Containers

Associações
3
Sumário da Apresentação
Hash com encadeamento em área separada

Tabelas Hash Abstratas (só Java)

Encadeamento Separado

Implementação

Construtor e Destrutor (C++)

Construtor e métodos getLength e purge (Java)

Inserção e exclusão de itens

Encontro de itens
Hash com encadeamento em área primária

Tabelas de Espalhamento Encadeadas

Implementação

Construtor e Destrutor (C++)

Construtor e métodos getLength e purge (Java)

Inserção e encontro de itens

Exclusão de itens
4
Sumário da Apresentação
Hash usando Endereçamento Aberto
 Sondagem linear
 Sondagem Quadrática
 Duplo Hashing
 Implementação
 Construtor e Destrutor
 Inserção de itens
 Encontro de itens
 Exclusão de itens
5
Espalhamento
Sumário do item Espalhamento
A idéia inicial de espalhamento
 Exemplo
Métodos de Espalhamento
 Método da Divisão
 Método do Meio do Quadrado
 Método da Multiplicação
7
A idéia 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 definição de uma função de espalhamento,
ou “hash”, como mostrado na figura abaixo:
x
"ett"
"två"
"tre“
"fyra“
"fem"
"sex“
h(x)
1
2
3
4
5
6
x
"sju“
"åtta“
"nio“
"tio“
"elva“
"tolv“
h(x)
7
8
9
10
11
12
8
Espalhamento em memória
Secundária
O Espalhamento em memória secundária é
o processo preferencial para a implantação
dos arquivos de acesso direto.
9
Espalhamento em Memória Secundária
1- Agrupar um determinado número de registros em uma unidade
com endereço comum chamada "bucket".
2- Calcular o espaço de armazenamento necessário para o arquivo.
Esse dimensionamento do arquivo depende da densidade de
empacotamento ou fator de carga que é a razão entre o
número de registros nos arquivos e a capacidade total dos
"buckets".
3- Escolher uma função "hash" que é a transformação a aplicar à
chave para obter o endereço do "bucket".
4- Optar por uma técnica de resolução do problema de
transbordamento. Ocorre transbordamento ou "overflow"
quando se endereça um registro a um "bucket" já cheio.
10
Buckets (1)
O arquivo é dividido em seções menores denominadas
"buckets", que podem conter um ou mais registros.
A função "Hash" atribui a cada registro um endereço de
"bucket" ("home address"), onde este pode ser acomodado.
O tamanho de “bucket” é determinado pelo número de registros
que este pode armazenar, ou ainda, pelo número de "slots" que
ele contém. Um "slot" é uma unidade de armazenamento que
contém espaço 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 características
físicas do meio de armazenamento. Logo, o tempo de
transporte do “bucket” para a memória principal é proporcional
ao tamanho do bucket.
11
Buckets (2)
Ocorre uma colisão quando durante uma inclusão de registros,
dois deles têm o mesmo endereço calculado pela função “hash”.
Estes registros são chamados sinônimos. As colisões não
constituem problemas enquanto não se atingir a capacidade do
"bucket" correspondente. A partir daí, ocorre transbordamento,
que consiste no fato de um registro não poder ser acomodado
em "home bucket".
Define-se como "home bucket" aquele que está associado ao
"home address" do registro, que fora calculado pela função
"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 à memória principal é
mais rápido comparado com o tempo de busca em memória
secundária, uma vez que o “bucket” será transferido para
memória principal.
12
Métodos de Espalhamento
Método do resto da Divisão
Para este caso a função hash é h(x) = x mod M, sendo M o
número de endereços disponíveis 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
posição h(x)-1 do array.
Os elementos do conjunto K são chamados de chaves.
É usual armazenar estas chaves em um array ou arquivo.
Imediatamente pode-se utilizar esta idéia para armazenar não
apenas cadeias de caracteres e sim objetos dos quais um dos
atributos seja uma chave do conjunto K.
A técnica de "hashing" proporciona uma recuperação de
registros extremamente rápida se comparada com a
recuperação seqüencial. O tempo de recuperação em arquivos
sequenciais cresce com o tamanho do arquivo, o que não ocorre
com o "hashing". No projeto de um arquivo de acesso direto os
fatores que é necessário considerar são os seguintes:
14
Método do Meio Quadrado
O espalhamento pelo meio do quadrado considera que M = 2k, o número de
endereços (“buckets”), é um múltiplo de 2. Para palavras de tamanho W, com w
bits as operações inteiras são feitas módulo W.
A função é hash de x é obtida elevando x ao quadrado módulo W e reduzindo este
número ao domínio {0,1,...,M-1} por meio da multiplicação por dois elevado a w-k
o que zera os w-k bits à esquerda.
O código que se segue mostra esta implementação
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
Método da Multiplicação
Uma variação do método do meio do quadrado é o método da
multiplicação, pelo qual hash de x não 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 representação binária é
10 011 110 001 101 110 111 100 110 111 001.
Sua inversa é
O código que se segue mostra esta implementação
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
Implementação das funções
Hash
Sumário do item
Implementação das funções Hash
Chaves Inteiras
Chaves de Ponto Flutuante
Chaves de Cadeias de Caracteres
Espalhamento de Objetos
Espalhamento de Containers
Associações
18
Fundamentos
As chaves dos objetos podem ser de quaisquer tipos de dados até
estruturas como associações ou containers.
Para um conjunto de chaves, K, e uma constante positiva M, uma
função hash é da forma h: K  {0,1,..., M-1}
É conveniente implementar a função h como uma composição de duas
funções f e g. A função f mapeia chaves em inteiros f: K  Z+
aonde Z+ é o conjunto dos inteiros não negativos. A função g mapeia
inteiros não negativos em {0, 1, ..., M-1}, g: Z+  {0, 1, ..., M-1}
Desde que sejam conhecidas as funções f e g, a função hash h é
definida como a composição delas: h = f  g
Ou seja, o valor de hash de uma chave x é dado por g(f(x)).
19
Implementação das funções
Hash
Implementação C++
Chaves Inteiras
A função f que mapeia chaves em inteiros para chaves
constituídas de inteiros é f(x) = x
Definição da Função 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 não nulo x pode ser expresso da forma x = m * 2e ,
sendo
A função f pode ser escrita
Sendo W o maior inteiro que pode ser expresso em uma palavra
do computador x e y colidirão se suas mantissas diferirem de
menos de 1/2W independente do valor dos expoentes.
Definição da Função 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 constituídas de cadeias de caracteres pode-se
concatenar as representações dos caracteres. Sendo, por exemplo
strings de comprimento 4
, estes strings podem ser
transformados em inteiros pela expressão
Sendo
potência de 2 pode-se escrever a função 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 não 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 polinômio em B, os coeficientes do
polinômio, si, podem ser calculados pela Regra de Horner, que
evita o cálculo 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 consideração de polinômio 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 consideração dos caracteres mais à esquerda e
mais à direita ou ainda utilizar a regra do polinômio com coeficientes
variáveis, por exemplo, obtidos de um array s.
Definição da Função 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
instâncias de tipos de dados C++ construídos em uma interface
abstrata Object. Usando o template as quatro classes Char, Int,
Double, and String são 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
implementações de todas as funções membros, inclusive a
função Hash.
Definição da função 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 função 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 função Container::Hash usa a função Accept para fazer um
visitante especial HashingVisitor visitar todos os objetos do
container. Quando visita um objeto chama a função Hash do
visitado e acumula o resultado.
Definição da função 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
Associações
Já que a função Accept é virtual todas as classes derivadas da classe
Container fornecerão as implementações correspondentes.
Utilizando o conceito de chave pode-se escrever A = {(k,v):kK, v V}
A função hash pode ser expressa como fA(k,v) = fK(k)
Sedo fk a função hash associada ao conjunto K.
Uma Association possui dois objetos
class Association : public Object, public Ownership {
Object* key;
Object* value;
...};
Para definir a função hash de uma associação basta chamar a função
membro hash do objeto para o qual a variável membro key aponta
Definição da Função Hash Member da classe Association
HshValue Association::Hash() const
{ return key->Hash(): }
29
Implementação das funções
Hash
Implementação Java
Método hashCode da classe Int
A função f que mapeia chaves em inteiros para
chaves constituídas de inteiros é f(x) = x
// pgm08_01.java
public class Int extends AbstractObject
{
protected int value;
public int hashCode()
{
return value;
}
// ...
}
31
Método hashCode da classe Dbl
A definição da função 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 constituídas de cadeias de caracteres pode-se
concatenar as representações dos caracteres. Sendo, por exemplo
strings de comprimento 4
, este string pode ser
transformado em inteiro pela expressão
Sendo B=27 potência de 2 pode-se escrever a função 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 não 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 polinômio em B, os coeficientes do
polinômio, si, podem ser calculados pela Regra de Horner, que
evita o cálculo 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 consideração de polinômio 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 consideração dos caracteres
mais à esquerda e mais à direita ou ainda utilizar a regra
do polinômio com coeficientes variáveis, por exemplo,
obtidos de um array s.
35
Método 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 função 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
Método 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
Associações
Já que a função Accept é virtual todas as classes derivadas da classe
Container fornecerão as implementações correspondentes.
Utilizando o conceito de chave pode-se escrever
A função hash pode ser expressa como
Sedo fk a função hash associada ao conjunto K.
Uma Association possui dois objetos
public class Association
extends AbstractObject
{
protected Comparable key;
protected Object value;
...};
Para definir a função hash de uma associação basta chamar a função
membro hash do objeto para o qual a variável key membro aponta
39
Método 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
Implementação do Espalhamento
Sumário do item Implantação do
Espalhamento
Hash com encadeamento em área separada

Tabelas Hash Abstratas (só Java)

Encadeamento Separado
Hash com encadeamento em área primária

Tabelas de Espalhamento Encadeadas
Hash usando Endereçamento Aberto

Sondagem linear

Sondagem Quadrática

Duplo Hashing

Implementação
42
Implementação do
Espalhamento
Implementação C++
Tabelas Hash
Definição 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
Implementação do Espalhamento
C++
Hash com encadeamento em área separada
Tabelas Hash
Definição das funções 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 variável membro de maneira adequada. A função
membro corresponde à composição h = g  f. A função membro
H recebe como argumento uma referencia constante a um
objeto e retorna o resultado Hash modulo length.
46
Encadeamento Separado
Tabela Hash usando Encadeamento Separado
47
Definição da Classe
ChainedHashTable
// pgm08_09.cpp
class ChainedHashTable : public HashTable
{
Array<LinkedList<Object*> > array;
public:
ChainedHashTable (unsigned int);
// ...
};
48
Definição das funções Purge
Member, Constructor e Destructor
da Classe ChainedHashTable (1)
// pgm08_10.cpp
ChainedHashTable::ChainedHashTable (unsigned int
_length) :
HashTable (_length),
array (_length)
{}
49
Definição das funções Purge
Member, Constructor e Destructor
da Classe ChainedHashTable (2)
// pgm08_10.cpp (Continuação)
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
Definição das Funções 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
Definição da Função 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
Implementação do Espalhamento
C++
Hash com encadeamento em área primária
Hash com encadeamento em área
primária
Quando é usado Hash com encadeamento em área primária o
transbordamento é tratado por listas encadeadas iniciadas nos
“home addresses”.
54
Definição 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
Definição das Funções 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
Definição das Funções Purge Member,
Constructor e Destructor da Classe
ChainedScatterTable e Constructor da Classe
ChainedScatterTable::Entry (2)
// pgm08_14.cpp (Continuação)
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
Definição das Funções 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
Definição das Funções Insert e Find
Member da Classe
ChainedScatterTable (2)
// pgm08_15.cpp (Continuação)
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
Definição da Função 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
Definição da Função Withdraw
Member da Classe
ChainedScatterTable (2)
// pgm08_16.cpp (Continuação)
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
Definição da Função Withdraw
Member da Classe
ChainedScatterTable (3)
// pgm08_16.cpp (Continuação)
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
Implementação do Espalhamento
C++
Hash usando Endereçamento Aberto
Tabelas de Espalhamento usando
Endereçamento Aberto (1)
A seqüência de sondagem é uma seqüência de funções
h0 , h1 ,..., hM 1


aonde hi é uma função hash hi: K  {0,1,...,M-1}
A inserção de um item x na tabela de espalhamento é feita
examinando as posições h0(x), h1(x),..., até encontrar uma célula
vazia.
A busca de um item na tabela segue a mesma
seqüência.
As seqüências de sondagem mais comuns são do tipo
hi ( x)  (h( x)  c(i)) mod M i

para i = 0,1,…,M-1
A função c(i) representa a estratégia de resolução de
transbordamentos.
64
Tabelas de Espalhamento usando
Endereçamento Aberto (2)
Sondagem Linear
Na sondagem linear a função c(i) é linear em i.
c(i )   (i )  
Ou, da maneira mais comum
c(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
Endereçamento Aberto (3)
Tabela de Espalhamento usando Endereçamento Aberto e
Sondagem Linear
66
Tabelas de Espalhamento usando
Endereçamento Aberto (4)
Sondagem Quadrática
c(i)  i 2  i  
Na sondagem linear a função c(i) é quadrática em i.
Ou, da maneira mais comum
c(i )  i 2
67
Tabelas de Espalhamento usando
Endereçamento Aberto (5)
Duplo Hashing
Pode-se gerar uma seqüência de sondagem por meio da
técnica de duplo hashing que usa duas funções h e h’ .
h : K  0,1,..., M 1
h' : K  1,2,..., M  1
A seqüência de sondagem é obtida da forma
hi ( x)  (h( x)  ih ' ( x)) mod M
68
Definição 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 não ocupada tenha o ponteiro para seu
objeto zerada e o estado default de todas as entradas é empty.
Este construtor default inicializa as duas variáveis membro de
maneira adequada.
70
Definição do Constructor e Destructor da
Classe OpenScatterTable e do Constructor
da Classe OpenScatterTable::Entry
// pgm08_18.cpp
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
Definição das Funções 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
Definição das Funções 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 função c define a seqüência de sondagem. Para sondagem linear
a função c é a função identidade.
A função membro FindUnoccupied é encontrar uma posição
desocupada. A rotina FindUnoccupied sonda o array de acorde
com a seqüência de sondagem determinada pela função c.
73
Definição das Funções 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
Definição das Funções FindMatch e
Find Member da Classe
OpenScatterTable (2)
// pgm08_20.cpp (Continuação)
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
Definição da Função 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 (Continuação)
if(array[j].state == Entry::empty)
break;
array[i] = array[j];
i = j;
}
array[i].state = Entry::empty;
array[i].object = 0;
--count;
}
78
Implementação Java
Implementação do Espalhamento
Java
Hash com encadeamento em área separada
Tabelas Hash
Interface HashTable
// pgm08_06.java
public interface HashTable extends SearchableContainer
{
double getLoadFactor();
}
81
Métodos 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
Métodos 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
}
Métodos 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
Método 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
}
Método 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
Implementação do Espalhamento
Java
Hash com encadeamento em área primária
Hash com encadeamento em
área primária
•Quando é usado
Hash com
encadeamento em
área primária 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
Métodos 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
Métodos constructor, getLength e
purge da classe
ChainedScatterTable (2)
// pgm08_14.java (Continuação)
public int getLength()
{
return array.length;
}
public void purge()
{
for(int i = 0; i < getLength (); ++i)
array [i].purge();
count = 0;
}
// ...
}
93
Métodos 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
}
Métodos insert e find da classe
ChainedScatterTable (2)
// pgm08_15.java (Continuação)
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
Método 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
Método withdraw da classe
ChainedScatterTable (2)
// pgm08_16.java (Continuação)
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
Método withdraw da classe
ChainedScatterTable (3)
// pgm08_16.java (Continuação)
if(!contained)
break;
j = array[j].next;
}
if(j == nil)
break;
array[i].object = array[j].object;
i = j;
}
98
Método withdraw da classe
ChainedScatterTable (3)
// pgm08_16.java (Continuação)
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
Implementação do Espalhamento
Java
Hash usando Endereçamento Aberto
Hash usando endereçamento
aberto
•Tabela de Espalhamento usando Endereçamento Aberto e Sondagem Linear
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
}
Métodos 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
}
Métodos 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
Métodos c, findUnoccupied e insert
da classe OpenScatterTable (2)
// pgm08_19.java (Continuação)
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
Métodos 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
}
Métodos findMatch e find da classe
OpenScatterTable (2)
// pgm08_20.java (Continuação)
public Comparable find(Comparable object)
{
int offset = findMatch(object);
if(offset >= 0)
return array[offset].object;
else
return null;
}
// ...
}
107
Método 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
}
Método 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
}
Método OpenScatterTableV2
withdraw (2)
// pgm08_22.java (Continuação)
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
Aplicação
Java
Aplicação 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
Aplicação Hash/scatter table –
contador de palavras (2)
// pgm08_23.java (Continuação)
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
Aplicação Hash/scatter table –
contador de palavras (3)
// pgm08_23.java (Continuação)
else
{
Association assoc = (Association) obj;
Counter counter = (Counter) assoc.getValue();
counter.increment();
}
}
out.println(table);
}
}
114
Aplicações
Aplicação da Hash/Scatter Table--Contando Palavras
Uma aplicação de espalhamento é a contagem do número de
ocorrências distintas de cada palavra contida em um arquivo
texto.
AplicaçõesAplicação da Hash/Scatter Table--Contando Palavras
(1)
//pgm08_23.cpp
class Counter : public Int {
public:
Counter (int i) : Int(i) {}
void operator ++ ()
{ ++datum; }
};
115
Aplicações
AplicaçõesAplicação da Hash/Scatter Table--Contando Palavras (2)
// pgm08_23.cpp (Continuação)
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
}
Implementação Java
Hierarquia de Classes
118
Tabelas Hash
Interface HashTable
// pgm08_06.java
public interface HashTable extends SearchableContainer
{
double getLoadFactor();
}
119
Aplicação Conta Palavras em Java
Hash com encadeamento em área separada
Métodos 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
Métodos 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
}
Métodos 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
}
Método 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
}
Método 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
Aplicação Conta Palavras em Java
Hash com encadeamento em área
primária
Hash com encadeamento em área
primária
Quando é usado Hash com encadeamento em área primária 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
Métodos 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
Métodos constructor, getLength e
purge da classe
ChainedScatterTable (2)
// pgm08_14.java (Continuação)
public int getLength()
{
return array.length;
}
public void purge()
{
for(int i = 0; i < getLength (); ++i)
array [i].purge();
count = 0;
}
// ...
}
132
Métodos 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
}
Métodos insert e find da classe
ChainedScatterTable (2)
// pgm08_15.java (Continuação)
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
Método 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
Método withdraw da classe
ChainedScatterTable (2)
// pgm08_16.java (Continuação)
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
Método withdraw da classe
ChainedScatterTable (3)
// pgm08_16.java (Continuação)
if(!contained)
break;
j = array[j].next;
}
if(j == nil)
break;
array[i].object = array[j].object;
i = j;
}
137
Método withdraw da classe
ChainedScatterTable (3)
// pgm08_16.java (Continuação)
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
Aplicação Conta Palavras em Java
Hash usando Endereçamento
Aberto
Tabelas de Espalhamento usando
Endereçamento Aberto (1)
A seqüência de sondagem é uma seqüência de funções
h0 , h1 ,..., hM 1


aonde hi é uma função hash hi: K  {0,1,...,M-1}
A inserção de um item x na tabela de espalhamento é feita
examinando as posições h0(x), h1(x),..., até encontrar uma célula
vazia.
A busca de um item na tabela segue a mesma
seqüência.
As seqüências de sondagem mais comuns são do tipo
hi ( x)  (h( x)  c(i)) mod M i

para i = 0,1,…,M-1
A função c(i) representa a estratégia de resolução de
transbordamentos.
140
Tabelas de Espalhamento usando
Endereçamento Aberto (2)
Sondagem Linear
Na sondagem linear a função c(i) é linear em i.
c(i )   (i )  
Ou, da maneira mais comum
c(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
Endereçamento Aberto (3)
Tabela de Espalhamento
usando Endereçamento
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
}
Métodos 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
}
Métodos 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
Métodos c, findUnoccupied e insert
da classe OpenScatterTable (2)
// pgm08_19.java (Continuação)
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
Métodos 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
}
Métodos findMatch e find da classe
OpenScatterTable (2)
// pgm08_20.java (Continuação)
public Comparable find(Comparable object)
{
int offset = findMatch(object);
if(offset >= 0)
return array[offset].object;
else
return null;
}
// ...
}
148
Método 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
}
Método 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
}
Método OpenScatterTableV2
withdraw (2)
// pgm08_22.java (Continuação)
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
Aplicação 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
Aplicação Hash/scatter table –
contador de palavras (2)
// pgm08_23.java (Continuação)
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
Aplicação Hash/scatter table –
contador de palavras (3)
// pgm08_23.java (Continuação)
else
{
Association assoc = (Association) obj;
Counter counter = (Counter) assoc.getValue();
counter.increment();
}
}
out.println(table);
}
}
154
Download