Tabelle hash - Dipartimento di Ingegneria dell`informazione e

Transcript

Tabelle hash - Dipartimento di Ingegneria dell`informazione e
Hash Tables
Ilaria Castelli
[email protected]
Università degli Studi di Siena
Dipartimento di Ingegneria dell’Informazione
A.A. 2009/2010
I. Castelli
Hash Tables, A.A. 2009/2010
1/42
Hash Tables
Indirizzamento diretto
Tabelle Hash
Risoluzione di collisioni
Indirizzamento aperto
I. Castelli
Hash Tables, A.A. 2009/2010
2/42
Introduzione
A volte è necessario disporre di strutture dati che fungano da
”dizionario”.
I
I
I
I
inserimento
ricerca
rimozione
NON sono necessarie altre operazioni (massimo, minimo,
ordinamento. . . )
Le hash tables sono strutture dati efficienti utili a questo scopo
...non sono l’unica soluzione possibile...
sotto alcune condizioni sono la soluzione più vantaggiosa
I. Castelli
Hash Tables, A.A. 2009/2010
3/42
Indirizzamento
Problema dell’indirizzamento: Disponiamo di un insieme di chiavi
prelevate da un universo U = {k0 , k1 , . . . km−1 }.
Ad ogni chiave sono associati una serie di dati.
i dati sono costituiti da un insieme di record
I
un record è una struttura dati eterogenea, contenente una
combinazione di elementi di diverso tipo. Gli elementi di un record
sono detti anche campi.
dati aggiuntivi
key
k0 Ilaria Castelli
201
[email protected]
k1 Edmondo Trentin
211
[email protected]
.....
.....
.....
118
[email protected]
k(m−1) Marco Maggini
I. Castelli
Hash Tables, A.A. 2009/2010
4/42
Indirizzamento
Scopo:
1
avere tempi di ricerca (look-up) rapidi (costanti O(1))
2
ottimizzare l’uso della memoria
dati aggiuntivi
key
k0 Ilaria Castelli
201
[email protected]
k1 Edmondo Trentin
211
[email protected]
.....
.....
.....
118
[email protected]
k(m−1) Marco Maggini
I. Castelli
Hash Tables, A.A. 2009/2010
5/42
Indirizzamento diretto
Soluzione semplice: tabelle ad indirizzamento diretto
creare uno spazio di memoria per ogni possibile chiave
ci sarà una corrispondenza diretta tra la chiave e lo spazio assegnato
al relativo record
Chiavi
Edmondo Trentin
Marco Maggini
Ilaria Castelli
I. Castelli
Record
Indici
1
Ilaria Castelli
201
[email protected]
2
Edmondo Trentin
211
[email protected]
.....
.....
118
[email protected]
.....
99
.....
Marco Maggini
Hash Tables, A.A. 2009/2010
6/42
Indirizzamento diretto
Semplificazione: consideriamo come chiavi i numeri interi
L’indirizzamento diretto è comodo quando l’insieme delle chiavi U è
piccolo
U (insieme di tutte le chiavi)
8
2
1
4
T[0...8]
−
0
−
1
−
2
3
0
7
−
K
(chiavi
effettive)
I. Castelli
3
5
6
key
dati aggiuntivi
3
4
5
5
6
6
−
7
−
8
Hash Tables, A.A. 2009/2010
7/42
Indirizzamento diretto
Per rappresentare l’insieme si usa un array T [0...(m − 1)]
Ogni posizione è associata ad una e una sola chiave dell’insieme U
Si assume che non esistano più elementi con la stessa chiave
T [ki ] punta all’elemento dell’insieme con la chiave ki (e alle sue
informazioni aggiuntive)
T [ki ] = N IL se non esiste nessun elemento con chiave ki
I. Castelli
Hash Tables, A.A. 2009/2010
8/42
1
2
1
2
1
2
Indirizzamento diretto - Operazioni
DIRECT−ADDRESS−SEARCH(T , k )
return T[ k ]
Ricerca
DIRECT−ADDRESS−INSERT (T , x )
T[ key [ x ] ] = x
Inserimento
DIRECT−ADDRESS−DELETE(T , x )
T [ k e y [ x ] ] = NIL
Rimozione
Queste tre operazioni richiedono tempo O(1)
I. Castelli
Hash Tables, A.A. 2009/2010
9/42
Indirizzamento diretto - Considerazioni
Gli elementi dell’insieme (i record) vengono memorizzati in strutture
dati esterne
Ogni posizione della tabella T contiene un puntatore alla struttura
dati corrispondente
È superfluo memorizzare la chiave dell’elemento
In alcune applicazioni gli elementi possono essere memorizzati
direttamente nella tabella
I. Castelli
Hash Tables, A.A. 2009/2010
10/42
Indirizzamento diretto - Considerazioni
Se | U | non è grande, allora l’array ha dimensioni “modeste”
In tal caso l’utilizzo dell’indirizzamento diretto è efficiente
Ricorda: deve esistere una posizione nell’array per ogni possibile
valore della chiave
Se il numero di chiavi necessarie è piccolo rispetto all’intero universo
delle chiavi sprechiamo molto spazio
Se | U | è molto grande può essere difficile (o impossibile) allocare la
memoria necessaria
Le hash tables sono un’alternativa efficiente alle tabelle con
indirizzamento diretto
I. Castelli
Hash Tables, A.A. 2009/2010
11/42
Indirizzamento diretto - Considerazioni
Se | U | non è grande, allora l’array ha dimensioni “modeste”
In tal caso l’utilizzo dell’indirizzamento diretto è efficiente
Ricorda: deve esistere una posizione nell’array per ogni possibile
valore della chiave
Se il numero di chiavi necessarie è piccolo rispetto all’intero universo
delle chiavi sprechiamo molto spazio
Se | U | è molto grande può essere difficile (o impossibile) allocare la
memoria necessaria
Le hash tables sono un’alternativa efficiente alle tabelle con
indirizzamento diretto
I. Castelli
Hash Tables, A.A. 2009/2010
11/42
Indirizzamento diretto
Esempio
Consideriamo un dizionario della lingua italiana con circa 130.000 parole.
K è l’insieme delle parole della lingua italiana =⇒| K |= 130.000
L = {a, b, c, . . . , z} è l’alfabeto =⇒| L |= 26
U è l’universo di tutte le possibili parole che possiamo costruire a
partire da L. Supponiamo parole di lunghezza massima 15.
|U | =
15
X
| L |i w 7 ∗ 1019
i=1
| K | = 130.000
I. Castelli
Hash Tables, A.A. 2009/2010
12/42
Hash Tables
Ind. diretto =⇒ l’elemento con chiave k è associato alla posizione k
Hashing =⇒ l’elemento con chiave k è associato alla posizione h(k)
U (insieme di tutte le chiavi)
T[0,...,m−1]
−
−
..........
−
h(k0) = h(k1)
−
K
k0
(chiavi
effettive) k2
h(k2)
k1
h(k3)
k3
−
−
I. Castelli
Hash Tables, A.A. 2009/2010
13/42
Hash Function
h(k) è detta funzione hash
h : U −→ {0, 1, . . . , m − 1}
Consente di calcolare la posizione nell’array, a partire dalla chiave k
I
I. Castelli
h(k) è il valore hash della chiave k
Hash Tables, A.A. 2009/2010
14/42
Hash Function
h(k) è detta funzione hash
h : U −→ {0, 1, . . . , m − 1}
Consente di calcolare la posizione nell’array, a partire dalla chiave k
I
h(k) è il valore hash della chiave k
L’obiettivo è ridurre la dimensione dell’array
Non sono necessarie | U | locazioni di memoria, ma solo m
I. Castelli
Hash Tables, A.A. 2009/2010
14/42
Hash Tables
Se | K || U | con gli array ad indirizzamento diretto si spreca molta
memoria!
Con le hash tables la quantità di memoria necessaria può essere
ridotta a Θ(| K |)
Il tempo necessario per una ricerca resta O(1) nel caso medio
Si ottiene un buon compromesso tra lo spazio occupato e il tempo
necessario per effettuare una ricerca
È possibile che vi siano collisioni se
keyi 6= keyj e h(keyi ) = h(keyj )
Se la funzione hash distribuisce in modo uniforme le chiavi nelle
posizioni dell’array, la probabilità di collisioni diminuisce
| U |> m, quindi evitare del tutto le collisioni è impossibile
I. Castelli
Hash Tables, A.A. 2009/2010
15/42
Gestione delle collisioni - Chaining
Si inseriscono tutti gli elementi con lo stesso valore hash in una lista
concatenata
U (insieme di tutte le chiavi)
T[0,...,m−1]
−
−
.........
−
k0
k1
−
−
K
(chiavi
effettive)
k0
k1
k2
k3
k2
−
k3
−
−
−
I. Castelli
Hash Tables, A.A. 2009/2010
16/42
1
2
3
1
2
3
1
2
3
Gestione delle collisioni - Chaining
T [h(k)] contiene un puntatore all’inizio della lista concatenata in
cui sono inseriti gli elementi con lo stesso valore hash h(k)
Set T [h(k)] = N IL non c’è nessun elemento con valore hash h(k)
Operazioni
CHAINED−HASH−SEARCH(T , k )
/∗ c e r c a l a c h i a v e k n e l l a
LIST−SEARCH(T [ h ( k ) ] , k )
l i s t a T [ h ( k ) ] ∗/
Ricerca
CHAINED−HASH−INSERT (T , x )
/∗ i n s e r i s c i x n e l l a l i s t a T [ h ( k e y [ x ] ) ] ∗/
LIST−INSERT (T [ h ( k e y [ x ] ) ] , x )
Inserimento
CHAINED−HASH−DELETE(T , x )
/∗ e l i m i n a x d a l l a l i s t a T [ h ( k e y [ x ] ) ] ∗/
LIST−DELETE(T [ h ( k e y [ x ] ) ] , x )
Rimozione
I. Castelli
Hash Tables, A.A. 2009/2010
17/42
Gestione delle collisioni - Chaining
Usando le liste:
L’inserimento richiede tempo O(1)
La ricerca richiede un tempo proporzionale alla lunghezza della lista
nel caso peggiore
La rimozione può essere compiuta in O(1) se la lista è bidirezionale
Se la lista è unidirezionale, prima di effettuare la rimozione di x,
bisogna anche cercare l’elemento che lo precede. Il tempo è quindi
proporzionale alla lunghezza della lista
I. Castelli
Hash Tables, A.A. 2009/2010
18/42
Analisi della tecnica di chaining
1
2
Caso peggiore
Caso medio
I
I
le performance dipendono dalla scelta della funione hash e dal modo
in cui distribuisce le chiavi negli m slot
supponiamo uniformità semplice della funzione hash, cioè che la
proababilità di ogni chiave di cadere nei vari slot sia uniforme
3
Si assume che il calcolo della funzione di hash h(k) sia costante:
O(1)
4
Si assume che l’accesso alle celle dell’array sia fatto in tempo
costante: O(1)
I. Castelli
Hash Tables, A.A. 2009/2010
19/42
Analisi della tecnica di chaining
1
Caso peggiore
I
I
2
tutti gli n elementi collidono su uno stesso valore di hash
si genera un’unica lista concantenata di lunghezza n
Caso medio
I
I
le performance dipendono dalla scelta della funione hash e dal modo
in cui distribuisce le chiavi negli m slot
supponiamo uniformità semplice della funzione hash, cioè che la
proababilità di ogni chiave di cadere nei vari slot sia uniforme
3
Si assume che il calcolo della funzione di hash h(k) sia costante:
O(1)
4
Si assume che l’accesso alle celle dell’array sia fatto in tempo
costante: O(1)
I. Castelli
Hash Tables, A.A. 2009/2010
19/42
Analisi della tecnica di chaining
1
Caso peggiore
I
I
2
tutti gli n elementi collidono su uno stesso valore di hash
si genera un’unica lista concantenata di lunghezza n
Caso medio
I
I
le performance dipendono dalla scelta della funione hash e dal modo
in cui distribuisce le chiavi negli m slot
supponiamo uniformità semplice della funzione hash, cioè che la
proababilità di ogni chiave di cadere nei vari slot sia uniforme
3
Si assume che il calcolo della funzione di hash h(k) sia costante:
O(1)
4
Si assume che l’accesso alle celle dell’array sia fatto in tempo
costante: O(1)
I. Castelli
Hash Tables, A.A. 2009/2010
19/42
Analisi della tecnica di chaining
1
Caso peggiore
I
I
2
tutti gli n elementi collidono su uno stesso valore di hash
si genera un’unica lista concantenata di lunghezza n
Caso medio
I
I
le performance dipendono dalla scelta della funione hash e dal modo
in cui distribuisce le chiavi negli m slot
supponiamo uniformità semplice della funzione hash, cioè che la
proababilità di ogni chiave di cadere nei vari slot sia uniforme
3
Si assume che il calcolo della funzione di hash h(k) sia costante:
O(1)
4
Si assume che l’accesso alle celle dell’array sia fatto in tempo
costante: O(1)
I. Castelli
Hash Tables, A.A. 2009/2010
19/42
Analisi della tecnica di chaining
1
Caso peggiore
I
I
2
tutti gli n elementi collidono su uno stesso valore di hash
si genera un’unica lista concantenata di lunghezza n
Caso medio
I
I
le performance dipendono dalla scelta della funione hash e dal modo
in cui distribuisce le chiavi negli m slot
supponiamo uniformità semplice della funzione hash, cioè che la
proababilità di ogni chiave di cadere nei vari slot sia uniforme
3
Si assume che il calcolo della funzione di hash h(k) sia costante:
O(1)
4
Si assume che l’accesso alle celle dell’array sia fatto in tempo
costante: O(1)
Def.
Si definisce il fattore di carico α per la tabella hash T come α =
il numero medio di elementi in una lista
I. Castelli
Hash Tables, A.A. 2009/2010
n
m
cioè
19/42
Analisi della tecnica di chaining - Ricerca senza successo
Teorema
In una tabella hash che risolve le collisioni per concatenazione una ricerca
senza successo richiede tempo medio pari a
Θ(1 + α)
assumendo uniformità semplice della funzione hash
Dimostrazione
1
se si ha uniformità semplice della funzione di hash, ogni chiave k può
cadere in modo equiprobabile in ognuno degli m slot
2
ogni lista è lunga α =
3
se la ricerca è senza successo esaminerò α elementi
4
il tempo per calcolare h(k) è O(1)
I. Castelli
n
m
Hash Tables, A.A. 2009/2010
20/42
Analisi della tecnica di chaining - Ricerca con successo
Teorema
In una tabella hash che risolve le collisioni per concatenazione una ricerca
con successo richiede tempo medio paria a
Θ(1 + α)
assumendo uniformità semplice della funzione hash
Dimostrazione
1
se si ha uniformità semplice della funzione di hash, ogni chiave k può
cadere in modo equiprobabile in ognuno degli m slot
2
l’analisi è più complessa: dipende dal punto della lista in cui
mediamente si trova l’elemento da trovare
3
si suppone che gli elementi vengano inseriti alla fine della lista (questa
ipotesi non cambia il risultato!)
I. Castelli
Hash Tables, A.A. 2009/2010
21/42
Analisi della tecnica di chaining - Ricerca con successo
4
5
l’elemento i-esimo viene inserito in una lista lunga in media
per trovare l’elemento i-esimo si deve
I
I
6
calcolare h(k)
esaminare mediamente
i−1
m
i−1
m elementi
il tempo medio per una ricerca è
n
n 1X
i−1
1X
T (i) =
1+
T (n) =
n
n
m
i=1
i=1
n
1 X
1
n(n − 1)
= 1+
(i − 1) = 1 +
nm
nm
2
i=1
α
1
= 1+ −
2
2m
Il tempo è Θ(1 + α)
I. Castelli
Hash Tables, A.A. 2009/2010
22/42
Analisi della tecnica di chaining
Conclusioni
1
Se il numero m di slot nella tabella è proporzionale al numero n di
elementi si ha n = O(m)
2
α=
3
La ricerca richiede tempo costante
4
Tutte le operazioni possono essere eseguite in tempo costante
I. Castelli
O(m)
m
= O(1)
Hash Tables, A.A. 2009/2010
23/42
Scelta della funzione hash - Assunzione di uniformità
Una buona funzione hash soddisfa l’assunzione di uniformità
semplice
Supponiamo che ogni chiave k sia pescata indipendentemente dalle
altre da U , con probabilità P (k). Allora
X
1
P (k) =
∀j = 0, 1, . . . , m − 1
m
k:h(k)=j
Partizionando U in sottoinsiemi tali che in ognuno cadano tutte le
chiavi che sono mappate su uno stesso valore di hash, allora vi è la
stessa probabilità di estrarre un elemento da uno qualsiasi di questi
sottoinsiemi.
Ma...
Raramente si conosce la distribuzione di probabilità P
Per questo motivo è necessario usare delle euristiche per ottenere
una buona funzione hash
Nota: si assume che le chiavi siano esprimibili come numeri naturali.
I. Castelli
Hash Tables, A.A. 2009/2010
24/42
Funzioni hash - Metodo della divisione
La posizione è data dal resto della divisione tra k ed m:
h(k) = k
mod m
È molto veloce, ma la scelta di m deve essere fatta in maniera opportuna
Cattiva scelta:
m = 2p
k è rappresentata su w bit: 0 ≤ k < 2w
h(k) = k mod m = k mod 2p =⇒ 0 ≤ h(k) < 2p
k ÷ 2p =⇒ shift di k a dx, di p posizioni
k
I. Castelli
mod 2p sono gli ultimi p bit di k
Hash Tables, A.A. 2009/2010
25/42
Funzioni hash - Metodo della divisione
Esempio:
k = 1010110010 =⇒ w = 10 (10 bit)
m = 10000 = 24 =⇒ p = 4, m = 16
k ÷ m = |101011
{z } , 0010
|{z} =⇒ h(k) = 0010
quoziente resto
Note:
Per calcolare h(k) si usa solo una piccola frazione dei bit della
chiave k
Molta informazione non viene usata!
I. Castelli
Hash Tables, A.A. 2009/2010
26/42
Funzioni hash - Metodo della divisione
Buona scelta:
Scegliere m come un numero primo non vicino ad una potenza di 2.
Esempio:
n = 2000 chiavi
collisioni gestite con la tecnica di chaining
vogliamo α w 3
Come si sceglie m?
2000
3
w 667
m = 701 è una buona scelta!
h(k) = k mod 701
I. Castelli
Hash Tables, A.A. 2009/2010
27/42
Funzioni hash - Metodo della moltiplicazione
Richiede due passi:
1
si moltiplica k per una costante 0 < A < 1, e si estrae la parte
frazionaria
2
si moltiplica il risultato per m e si prende la parte intera
h(k) = bm (kA mod 1)c
= bm (kA − bkAc)c
È più lento, ma non ci sono valori critici per m
va bene con qualsiasi valore
di 0 < A < 1.
√
5−1
Knuth suggerisce A = 2 w 0.6180339 . . .
se m = 2p si semplifica l’implementazione
I. Castelli
Hash Tables, A.A. 2009/2010
28/42
Funzioni hash - Metodo della moltiplicazione
Esempio:
m = 1000
k = 123
A w 0.6180339
I. Castelli
Hash Tables, A.A. 2009/2010
29/42
Funzioni hash - Metodo della moltiplicazione
Esempio:
m = 1000
k = 123
A w 0.6180339
h(k) = b1000 (123 ∗ 0.6180339 mod 1)c
= b1000 (76.0181697 mod 1)c
= b1000 ∗ 0.0181697c
= b18.1697c
= 18
I. Castelli
Hash Tables, A.A. 2009/2010
29/42
Funzioni hash - Metodo della moltiplicazione
Se m = 2p si implementa facilmente:
k è codificato su w bit (dimensione di una parola in memoria)
bA2w c è codificato su w bit
il prodotto k ∗ bA2w c sta al più su 2w bit
k ∗ bA2w c = r1 2w + r0
h(k) corrisponde ai p bit più significativi di r0
w bits
k
x
floor(A*2^w)
r1
r0
p bits
h(k)
I. Castelli
Hash Tables, A.A. 2009/2010
30/42
Gestione delle collisioni - Indirizzamento aperto
Tutti gli elementi vengono inseriti nella tabella stessa.
Ogni posizione della tabella contiene, o un elemento, o N IL
I
NON ci sono puntatori
Non ci sono strutture dati esterne alla tabella
Inserimento: se si ha una collisione, si cerca uno slot “alternativo” in
cui inserire
Ricerca: si esaminano sistematicamente le posizioni della
tabella finché, o si trova l’elemento, oppure è chiaro che non è
presente
I
invece di seguire i puntatori, si calcola una sequenza di posizioni in cui
l’elemento potrebbe trovarsi
La tabella può riempirsi completamente
α≤1
I. Castelli
Hash Tables, A.A. 2009/2010
31/42
Indirizzamento aperto - Scansione
Per inserire o cercare un elemento, si esamina una sequenza di posizioni
finché si trova l’elemento, oppure N IL
la sequenza hs0 , s1 , . . . , sm−1 i è una permutazione degli indici
h0, 1, . . . , m − 1i della tabella
dipende da k
la funzione hash è
h : U × {0, 1, . . . , m − 1} −→ {0, 1, . . . , m − 1}
la sequenza di scansione è
hh(k, 0), h(k, 1), . . . , h(k, m − 1)i
I. Castelli
Hash Tables, A.A. 2009/2010
32/42
Indirizzamento aperto - Inserimento
Si vuole inserire un elemento con k = 706
T[0,...,m−1]
−
0
−
1
772
2
3
..........
−
887
983
−
−
I. Castelli
Hash Tables, A.A. 2009/2010
m−1
33/42
Indirizzamento aperto - Inserimento
Si vuole inserire un elemento con k = 706
T[0,...,m−1]
h(k, 0) = h(706, 0)
−
0
−
1
772
2
3
..........
−
887
collisione!
983
−
−
I. Castelli
Hash Tables, A.A. 2009/2010
m−1
33/42
Indirizzamento aperto - Inserimento
Si vuole inserire un elemento con k = 706
T[0,...,m−1]
h(k, 0) = h(706, 0)
h(k, 1) = h(706, 1)
collisione!
−
0
−
1
772
2
3
..........
−
887
983
−
−
I. Castelli
Hash Tables, A.A. 2009/2010
m−1
33/42
Indirizzamento aperto - Inserimento
Si vuole inserire un elemento con k = 706
T[0,...,m−1]
h(k, 0) = h(706, 0)
h(k, 1) = h(706, 1)
h(k, 2) = h(706, 2)
−
0
−
1
772
2
3
..........
−
887
983
vuoto!
706
−
I. Castelli
Hash Tables, A.A. 2009/2010
m−1
33/42
1
2
3
4
5
6
7
8
9
0
1
2
3
Indirizzamento aperto - Inserimento
HASH−INSERT (T , k )
i = 0
repeat
/∗ c a l c o l o l o s l o t ∗/
j = h(k , i )
i f T [ j ] = NIL
/∗ s e e ’ v u o t o i n s e r i s c o ∗/
then T[ j ] = k
return j
else i = i + 1
until i = m
/∗ r a g g i u n t a l a f i n e d e l l a t a b e l l a ∗/
e r r o r " hash table overflow "
I. Castelli
Hash Tables, A.A. 2009/2010
La ricerca dello slot in
cui inserire termina
quando si trova una
posizione libera
Se la tabella è piena non
si può inserire
34/42
1
2
3
4
5
6
7
8
9
0
1
Indirizzamento aperto - Ricerca
HASH−SEARCH(T , k )
i = 0
repeat
/∗ c a l c o l o l o s l o t ∗/
j = h(k , i )
i f T[ j ] = k
then return j
else i = i + 1
u n t i l T [ j ] = NIL o r i = m
/∗ r a g g i u n t a l a f i n e d e l l a t a b e l l a ∗/
e r r o r " hash table overflow "
Esplora la stessa
sequenza di slot della
procedura di inserimento
La ricerca termina:
se si trova la chiave
oppure se si trova una posizione vuota
(se k fosse stata inserita, sarebbe lı̀!)
I. Castelli
Hash Tables, A.A. 2009/2010
35/42
Indirizzamento aperto - Rimozione
1
Se si gestissero le collisioni con la tecnica di chaining sarebbe
semplice: è sufficiente eliminare un elemento dalla lista.
2
Nel caso dell’indirizzamento aperto la rimozione è un’operazione
delicata.
I. Castelli
Hash Tables, A.A. 2009/2010
36/42
Indirizzamento aperto - Rimozione
Se si gestissero le collisioni con la tecnica di chaining sarebbe
semplice: è sufficiente eliminare un elemento dalla lista.
Nel caso dell’indirizzamento aperto la rimozione è un’operazione
delicata.
1
2
Si vuole rimuovere k2
−
Si inserisce N IL nella posizione che era
occupata da k2.
−
k9
h(k9,1)
k1
h(k1,0)
−
k2
−
h(k2,0) = h(k9,0)
Attenzione: h(k9, 0) = h(k2, 0)!
Che succede se si cerca k9?
Soluzione: non inseriamo N IL, ma un
apposito marker DELET ED
I
...........
−
−
I. Castelli
I
la procedura di inserimento deve trattare
DELET ED come una posizione libera
la procedura di ricerca non deve fermarsi
quando trova DELET ED
Hash Tables, A.A. 2009/2010
36/42
Indirizzamento aperto - Rimozione
Se si gestissero le collisioni con la tecnica di chaining sarebbe
semplice: è sufficiente eliminare un elemento dalla lista.
Nel caso dell’indirizzamento aperto la rimozione è un’operazione
delicata.
1
2
Si vuole rimuovere k2
−
Si inserisce N IL nella posizione che era
occupata da k2.
−
k9
h(k9,1)
k1
h(k1,0)
−
−
−
h(k2,0) = h(k9,0)
Attenzione: h(k9, 0) = h(k2, 0)!
Che succede se si cerca k9?
Soluzione: non inseriamo N IL, ma un
apposito marker DELET ED
I
...........
−
−
I. Castelli
I
la procedura di inserimento deve trattare
DELET ED come una posizione libera
la procedura di ricerca non deve fermarsi
quando trova DELET ED
Hash Tables, A.A. 2009/2010
36/42
Indirizzamento aperto - Rimozione
Se si gestissero le collisioni con la tecnica di chaining sarebbe
semplice: è sufficiente eliminare un elemento dalla lista.
Nel caso dell’indirizzamento aperto la rimozione è un’operazione
delicata.
1
2
Si vuole rimuovere k2
−
Si inserisce N IL nella posizione che era
occupata da k2.
−
k9
h(k9,1)
k1
h(k1,0)
−
−
−
h(k2,0) = h(k9,0)
Attenzione: h(k9, 0) = h(k2, 0)!
Che succede se si cerca k9?
Soluzione: non inseriamo N IL, ma un
apposito marker DELET ED
I
...........
−
−
I. Castelli
I
la procedura di inserimento deve trattare
DELET ED come una posizione libera
la procedura di ricerca non deve fermarsi
quando trova DELET ED
Hash Tables, A.A. 2009/2010
36/42
Indirizzamento aperto - Rimozione
Se si gestissero le collisioni con la tecnica di chaining sarebbe
semplice: è sufficiente eliminare un elemento dalla lista.
Nel caso dell’indirizzamento aperto la rimozione è un’operazione
delicata.
1
2
Si vuole rimuovere k2
−
Si inserisce N IL nella posizione che era
occupata da k2.
−
k9
h(k9,1)
k1
h(k1,0)
−
DELETED
−
h(k2,0) = h(k9,0)
Attenzione: h(k9, 0) = h(k2, 0)!
Che succede se si cerca k9?
Soluzione: non inseriamo N IL, ma un
apposito marker DELET ED
I
...........
−
−
I. Castelli
I
la procedura di inserimento deve trattare
DELET ED come una posizione libera
la procedura di ricerca non deve fermarsi
quando trova DELET ED
Hash Tables, A.A. 2009/2010
36/42
Uniformità della funzione hash
Ipotesi di uniformità
Si assume che, per ogni chiave k, sia equamente probabile una
qualunque delle m! possibili permutazioni delle posizioni nella tabella
È una generalizzazione dell’ipotesi di uniformità semplice.
In questo caso la funzione hash non restituisce una sola posizione, ma
un’intera sequenza.
È difficile definire una funzione di hashing che sia davvero uniforme
Le tecniche maggiormente usate sono:
I
I
I
I. Castelli
Scansione lineare
Scansione quadratica
Double hashing
Hash Tables, A.A. 2009/2010
37/42
Scansione lineare
Data una funzione hash h0 : U −→ {0, 1, . . . , m − 1}, il metodo di
scansione lineare usa la funzione hash
h(k, i) = h0 (k) + i
mod m
i = 0, . . . , m − 1
Si genera una sequenza di posizioni contigue l’una all’altra
I
T [h0 (k)], T [h0 (k) + 1],. . . ,T [m − 1],T [0],. . . ,T [h0 (k) − 1]
Si ottiene una sequenza diversa per ogni possibile posizione di
partenza
I
m possibili sequenze, su m!
Facile da implementare
Agglomerazione primaria: le posizioni occupate si accumulano in
lunghi tratti contigui
I
I. Castelli
Come influisce questo sul tempo necessario per la ricerca?
Hash Tables, A.A. 2009/2010
38/42
Scansione quadratica
Data una funzione hash h0 : U −→ {0, 1, . . . , m − 1}, il metodo di
scansione quadratica usa la funzione hash
h(k, i) = h0 (k) + c1 i + c2 i2
mod m
i = 0, . . . , m − 1
dove c1 e c2 sono costanti fissate a priori
La posizioni dipendono quadraticamente da i
Funziona meglio della scansione lineare, ma c1 e c2 devono essere
scelte in modo che la sequenza scansioni l’intera tabella.
Si ottiene una sequenza diversa per ogni possibile posizione di
partenza
I
m possibili sequenze, su m!
Agglomerazione secondaria:
h(k1 , 0) = h(k2 , 0) =⇒ h(k1 , 1) = h(k2 , 1) =⇒ . . .
I. Castelli
Hash Tables, A.A. 2009/2010
39/42
Double hashing
Data due funzioni hash h1 : U −→ {0, 1, . . . , m − 1} e
h2 : U −→ {0, 1, . . . , m − 1}, il metodo di double hashing usa la
funzione hash
h(k, i) = (h1 (k) + ih2 (k))
mod m
i = 0, . . . , m − 1
È uno dei migliori metodi esistenti
Le posizioni successive alla prima dipendono da h2 mod m
A differenza degli altri metodi, dipende in due modi da k.
Nota: i valori h1 (k) e h2 (k) sono indipendenti l’uno dall’altro.
Ogni possibile coppia (h1 (k), h2 (k)) genera una sequenza diversa
I
m2 possibili sequenze
È il metodo che si avvicina di più allo schema ideale di hashing
uniforme
I. Castelli
Hash Tables, A.A. 2009/2010
40/42
Double hashing
Nota:
È necessario che h2 (k) ed m siano primi tra loro.
Se hanno un divisore comune d, si generano ciclicamente sempre le
stesse posizioni. Non si visita mai l’intera tabella ma solo (1/d)-esimo
delle possibili posizioni.
Di solito si usa m primo e si sceglie h2 in modo che generi sempre
numeri minori di m
Esempio:
h1 (k) = k mod m
h2 (k) = 1 + (k mod m0 ), con m0 < m (m − 1,o m − 2)
I. Castelli
Hash Tables, A.A. 2009/2010
41/42
Indirizzamento aperto - Analisi
Ricerca senza successo
Data una tabella hash a indirizzamento aperto con fattore dicarico α < 1,
1
,
il numero medio di accessi di una ricerca senza successo è al più 1−α
assumendo uniformità della funzione hash
Ricerca con successo
Data una tabella hash a indirizzamento aperto con fattore di carico α < 1,
1
il numero medio di accessi di una ricerca con successo è al più α1 ln 1−α
,
assumendo uniformità della funzione hash e che ogni chiave sia ricercata
nella tabella in modo equamente probabile
I. Castelli
Hash Tables, A.A. 2009/2010
42/42