Sei sulla pagina 1di 42

Algoritmi e Strutture Dati

Capitolo 7 - Tabelle hash

Alberto Montresor
Università di Trento

This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike License. To view a
copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/2.5/ or send a letter to Creative
Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.

© Alberto Montresor 1
Introduzione

✦ Dizionario (reloaded):
✦ Struttura dati per memorizzare insiemi dinamici di coppie
(chiave, valore)
✦ Il valore è un “dato satellite”
✦ Dati indicizzati in base alla chiave
✦ Operazioni: insert(), remove() e lookup()

✦ Applicazioni:
✦ Le tabelle dei simboli di un compilatore a int
✦ La gestione della memoria nei
b double
sistemi operativi

© Alberto Montresor 2
Introduzione

 Possibili implementazioni e relativi costi

Array Array Alberi Performance


Lista
non ordinato ordinato (abr, rb, ...)e ideale

insert() O(1) O(n) O(1) O(log n) O(1)

looup() O(n) O(log n) O(n) O(log n) O(1)

remove() O(n) O(n) O(n) O(log n) O(1)

© Alberto Montresor 3
Notazione

✦ U – Universo di tutte le possibili chiavi


✦ K – Insieme delle chiavi effettivamente memorizzate
✦ Possibili implementazioni
✦ |U| corrisponde al range [0..m-1], |K| ~ |U| →
✦ tabelle ad indirizzamento diretto
✦ U è un insieme generico, |K| << |U| →
✦ tabelle hash

© Alberto Montresor 4
Tabelle a indirizzamento diretto

✦ Implementazione: nil

Basata su array ordinari


U k0
k1

k2
✦ L'elemento con chiave nil
k1
k è memorizzato nel k3
K k3
k4
k-esimo “slot”del vettore k5 nil
✦ Se |K| ~ |U|: k5

✦ Non sprechiamo (troppo) spazio


chiave
✦ Operazioni in tempo O(1) nel caso peggiore

✦ Se |K| << |U|: soluzione non praticabile


✦ Esempio: studenti ASD con chiave “n. matricola” valore

© Alberto Montresor 5
Tabelle hash 0

✦ Tabelle hash:
U H(k1)
✦ Un vettore A[0..m-1] k1 H(k4)
k4
Una funzione hash k2
K

k5
H: U → {0,..,m-1} k3
H(k2),H(k5)
collisione
✦ Indirizzamento hash:
H(k3)
✦ Diciamo che H(k) è il valore hash della chiave k
✦ Chiave k viene “mappata” nello slot A[H(k)]
m–1
✦ Quando due o più chiavi nel dizionario hanno lo
stesso valore hash, diciamo che è avvenuta una collisione

✦ Idealmente: vogliamo funzioni hash senza collisioni

© Alberto Montresor 6
Problema delle collisioni

✦ Utilizzo di funzioni hash perfette


✦ Una funzione hash H si dice perfetta se è iniettiva, ovvero:
∀u, v ∈ U : u �= v ⇒ H(u) �= H(v)
✦ Si noti che questo richiede che m ≥ |U|

✦ Esempio:
✦ Studenti ASD solo negli ultimi tre anni
✦ Distribuiti fra 234.717 e 235.716
✦ H(k) = k - 234.717, m = 1000

✦ Problema: spazio delle chiavi spesso grande, sparso, non conosciuto


✦ E' spesso impraticabile ottenere una funzione hash perfetta

© Alberto Montresor 7
he
nasia scorrelato
funzione dalla
hash non struttura essa
è semplice; dell’input (la chiave
deve ricavare stessa).
l’output Da qui il termine “hash”,
(un numero
elato Funzioni
dalla hashdell’input (la chiave stessa). Da qui il termine “hash”,
struttura
glese significa “tritare” o “polpetta”: si sminuzza la chiave in pezzettini che sono
ficain“tritare”
ati modo o “polpetta”:
da formare si intero
un sminuzzache lasia
chiave
il in “casuale”
più pezzettini che sono
possibile. Ovviamente l’al-
✦ Se le collisioni sono inevitabili
da formare un intero che sia il più “casuale” possibile. Ovviamente l’al-
che calcola la funzione hash non è casuale, in quanto se si ricalcola più volte H(k)
la funzione hash non
✦ almeno è casuale,diinminimizzare
cerchiamo quanto se si ilricalcola
loro più volte H(k)
numero
ssa chiave k si ottiene sempre lo stesso valore, ma l’indirizzo hash si comporta da un
k si ottiene sempre lo stesso valore, ma l’indirizzo hash si comporta da un
vista statistico
ico come se fossecome
✦ vogliamo se fosseche
statofunzioni
davvero stato davvero
con uno prodotto
distribuiscano
prodotto lancicon
uniformemente
o più unodile
casuali ouna
più lanci
chiavi casuali
negli indicidi una
[0...m-1] della tabella hash
buona funzione
ione hash hash deveilminimizzare
deve minimizzare il numero
numero di collisioni di collisioni
presenti nel sistema;presenti nel sistema;
✦ Uniformità semplice:
teri
ossibilidefinire
per criteriquesta proprietà
per definire è dettoproprietà
questa uniformitàèsemplice: detta P (k)semplice:
detto uniformità la detta P (k) la
chiave
tà ✦siasia
che kuna inserita
chiave nella
P(k) la
k sia tabella,
inseritasiache
probabilità una
nella chiavesia
tabella, k sia inserita nella tabella

✦ sia Q(i) = �
P (k) la probabilità che una chiave qualsiasi, finisca nella
Q(i) = P (k)
cella i. k:H(k)=i
k:H(k)=i
a chiave✦qualsiasi finisca nella
Una funzione celladella
H gode i. Unaproprietà
funzione di gode della proprietà
H uniformità semplice se
ilitàseche
ice ∀i ∈una {0,chiave
...,m − qualsiasi
1} : Q(i)finisca
= 1/m. nella cella i. Una funzione H gode della proprietà
mità
zioni semplice se ∀i ∈ {0,
hash, è conveniente . . . , m −la1}
considerare : Q(i) = 1/m.
rappresentazione binaria bin(k)
chiave kfunzioni
efinire non è numerica,
hash, èbin(k) è data dalla
conveniente concatenazione
considerare della rappre-
la rappresentazione binaria bin(k)
i ciascun
ave k. Secarattere
la chiave cheklanon
compone. In tutti bin(k)
è numerica, i linguaggi di programmazione
è data dalla concatenazione della rappre-
primitiva (chiamiamola ord) che applicata ad un carattere, restituisce un
e binaria di ciascun carattere che la compone. In tutti i linguaggi di programmazione
ro ordinale del carattere nell’insieme dei caratteri ammessi. È altresı̀ utile
ail funzione
numero primitiva
intero
© Alberto Montresor
(chiamiamola
rappresentato ord) che
da una stringa applicata
binaria ad un
b. In questo carattere, restituisce un
modo, 8
Funzioni hash

✦ Per poter ottenere una funzione hash con uniformità semplice, la distribuzione
delle probabilità P deve essere nota
✦ Esempio:
✦ U numeri reali in [0,1] e ogni chiave ha la stessa probabilità di essere scelta,
allora
H(k) = �km�
soddisfa la proprietà di uniformità semplice

✦ Nella realtà
✦ La distribuzione esatta può non essere (completamente) nota
✦ Si utilizzano allora tecniche “euristiche”

© Alberto Montresor 9
Funzioni hash

✦ Assunzioni:
✦ Tutte le chiavi sono equiprobabili: P(k) = 1 / |U|
✦ Semplificazione necessaria per proporre un meccanismo generale
✦ Le chiavi sono valori numerici non negativi
✦ E' possibile trasformare una chiave complessa in un numero
✦ ord(c): valore ordinale del carattere c
✦ bin(k): rappresentazione binaria della chiave k, concatenando i valori
ordinali dei caratteri che lo compongono
✦ int(k): valore numerico associato ad una chiave k
✦ Esempio:
✦ bin(“DOG”) → ord(‘D’) ord(“O”) ord(“G”)

→ 01000100 01001111 01000111


✦ int(“DOG”) → 68 ⋅ 2562 + 79 ⋅ 256 + 71

→ 4.476.743

© Alberto Montresor 10
Funzioni hash

✦ Nei prossimi esempi


✦ ord(‘a’) = 1, ord(‘b’)=2, ..., ord(‘z’)=26, ord(‘b’)=32
✦ b rappresenta lo spazio
✦ Sono sufficienti 6 bit per rappresentare questi caratteri

✦ Si considerino le seguente due stringhe: “weberb” e “webern”


✦ Rappresentazione binaria
✦ bin(“weberb”) = 010111 000101 000010 000101 010010 100000
✦ bin(“webern”) = 010111 000101 000010 000101 010010 001110

✦ Rappresentazione intera
✦ int(“weberb”) = 23·645 +5·644 +2·643 +5·642 +18·641 +32·640 = 24.780.493.966
✦ int(“webern”) = 23·645 +5·644 +2·643 +5·642 +18·641 +14·640 = 24.780.493.984

© Alberto Montresor 11
Funzioni hash - Estrazione

✦ Assunzioni
✦ m=2p

✦ Come calcolare H(k)


✦ H(k) = int(b), dove b è un sottoinsieme di p bit presi da bin(k)

✦ Esempio:
✦ m =28 = 256, bit presi dalla posizione 15 alla posizione 22
✦ bin(“weberb”) = 010111 000101 000010 000101 010010 100000
✦ bin(“webern”) = 010111 000101 000010 000101 010010 001110
✦ da cui si ottiene:
✦ H(“weberb”) = bin(00100001) = 33
✦ H(“webern”) = bin(00100001) = 33

© Alberto Montresor 12
Funzioni hash: XOR

✦ Assunzioni
✦ m=2p

✦ Come calcolare H(k)


✦ H(k) = int(b), dove b è dato dalla somma modulo 2, effettuata bit a bit,
di diversi sottoinsiemi di p bit di bin(k)

✦ Esempio:
✦ m =28 = 256, 5 gruppi di 8 bit, 40 bit ottenuti con 4 zeri di “padding”
✦ H(“weberb”) = int(01011100⊕01010000⊕10000101⊕01001010⊕00000000)
= int(11000011) = 195
✦ H(“webern”) = int(01011100⊕01010000⊕10000101⊕01001000⊕11100000)
= int(00100001) = 33

© Alberto Montresor 13
Funzioni hash: metodo della divisione

✦ Assunzioni:
✦ m dispari, meglio se primo

✦ Procedimento di calcolo
✦ H(k) = k mod m

✦ Esempio:
✦ m =383
✦ H(“weberb”) = 24.780.493.966 mod 383 = ?
✦ H(“webern”) = 24.780.493.984 mod 383 = 242

✦ Nota: il valore m deve essere scelto opportunamente

© Alberto Montresor 14
Funzioni hash

✦ Non vanno bene:


✦ m=2p : solo i p bit più significativi vengono considerati
✦ m=2p-1 : permutazione di stringhe in base 2p hanno lo stesso valore hash
✦ Domanda: Dimostrazione

✦ Vanno bene:
✦ Numeri primi, distanti da potenze di 2 (e di 10)

© Alberto Montresor 15
dopo aver espanso
bit. H(Weberb) a destra bin(k)
= int(11000011) = con
195 quattro
mentrezeri in modo che=bin(k)
H(Webern) 40
sia formato=da33.
int(00100001)
O 7. TABELLE
bit. HASH = int(11000011) = 195 mentre H(Webern) = int(00100001)
H(Weberb) 123 = 33.
Funzioni
Infatti, hash:
indicando ⊕ la somma bit a bit modulo 2, si ottiene:
conMoltiplicazione
Infatti, indicando con ⊕ la somma bit a bit modulo 2, si ottiene:
metodi 11000011 = 01011100
di generazione di indirizzi 01010000
⊕ hash sono i⊕ 10000101
seguenti. I ⊕ 01001010
primi due ⊕ 00000000
presuppongono
✦ Assunzioni
11000011 = 01011100 ⊕ 01010000 ⊕ 10000101 ⊕ 01001010 ⊕ 00000000
00100001
er qualche = 01011100
p; il terzo lavora bene ⊕ 01010000
con tutti i ⊕ 10000101
valori 01001000
di m; il⊕quarto ⊕ 11100000
presuppone m
00100001
✦ m numero = 01011100
qualsiasi ⊕ 01010000
(potenze ⊕ 10000101 ⊕ 01001000 ⊕ 11100000
2 consigliate)
glio se primo):
Benché ✦H(Webern) sia uguale a 33, come nel caso (a), la collisione è stata eliminata.
Benché
C una costante reale,
H(Webern) 0 < Ca<33,
sia uguale 1 come nel caso (a), la collisione è stata eliminata.
one: = int(b), dove è un sottoinsieme
Poiché si usano 6 bit per rappresentare ciascun
H(k) b di pcarattere
bit di bin(k),
della solitamente estratti
chiave, int(bin(Webern)) è
(3) Poiché si usano 6 bit per rappresentare ciascun carattere della chiave, int(bin(Webern)) è
osizioni centrali;
interpretato come un numero
✦ Procedimento diun
calcoloin base 2 = 64.
6
interpretato come numero in base 26 = 64.
(k) = int(b), dove b è dato dalla somma modulo 2, effettuata bit a bit, di diversi
iemi di p bit di = int(bin(Webern))
✦ i = iint(bin(k))
i = int(bin(Webern))
bin(k);
icazione:✦ H(k)==23 ·=64 + 55· 64 + 24 · 64 + 35 numero
64 + 18 64 +1 14 64
5 4 3 2 1 0
�m(iC − �iC�)�, m · ·
23 · 64 + 5 · 64 + 2 · 64 + 5 · 64 + 18 · 64 + 14 · 640 di
dove è un 2qualsiasi (le ·
potenze
bene, anzi sono=consigliate),
64(64(64(64(23
= i è int(bin(k))
64(64(64(64(23 · 64 +
· 645)+e+5)
C2)è++
un
2) numero
5)
+ +
5)18)
+ reale,
+ 14.
18) + 0 < C < 1;
14.
✦ Esempio
ne: H(k) è√uguale al resto della divisione di int(bin(k)) per m.

Sia C = ✦ C = ( 1)/2
( 5 − m=
5 − e1)/2 256. Allora
= 256.
.4 (Funzioni hash). Si supponga che leAllora
Sia em
chiavi siano di 6 caratteri alfanumerici.
lunghe sono troncate,
✦ H(Webern) mentre
= �m(iC
H(Webern) chiavi
= −più
�m(iC −corte
�iC�)� =sono
�iC�)� espanse
= �256
�256 a destra con
· 0.9996833801
· 0.9996833801 . spazi.
. . .� Si
==255.
. .� 255.
(A) = 1, ord(B) = 2, . . ., ord(Z) = 26 e ord(b) = 32, dove b indica lo spazio,
Il calcolo
Il calcolo di H(Weberb)
di H(Weberb) è lasciato
è lasciato per esercizio.
per esercizio.
entazione di ogni ordinale su 6 bit. Per le chiavi Weberb e Webern si ottengono
rappresentazioni su 36 bit, dove si sono evidenziati per chiarezza i 6 gruppi di 6 bit
entano i caratteri della chiave:
bin(Weberb)
© Alberto Montresor = 010111 000101 000010 000101 010010 100000 16
Funzioni hash

✦ Come implementare il metodo della moltiplicazione:


✦ Si scelga un valore m=2p
✦ Sia w la dimensione in bit della parola di memoria: k, m ≤ 2w
✦ Sia s = ⎣C⋅2w⎦
✦ k⋅s può essere scritto come r1 ⋅2w+ r0
✦ r1 contiene la parte intera di kA w bit
✦ r0 contiene la parte frazionaria di kA
✦ Ritorniamo i p bit più significativi di r0 k
× s = ⎣C⋅2w⎦

r1 r0
estrai p bits
H(k)

© Alberto Montresor 17
Funzioni hash - continua

✦ Non è poi così semplice...


✦ Il metodo della moltiplicazione suggerito da Knuth non è poi così buono....

✦ Test moderni per valutare


✦ Avalanche effect:
✦ Se si cambia un bit nella chiave, deve cambiare almeno la metà dei bit del
valore hash
✦ Test statistici (Chi-square)
✦ Funzioni crittografiche (SHA-1)

© Alberto Montresor 18
Problema delle collisioni

✦ Abbiamo ridotto, ma non eliminato, il numero di collisioni


✦ Come gestire le collisioni residue?
✦ Dobbiamo trovare collocazioni alternative per le chiavi
✦ Se una chiave non si trova nella posizione attesa, bisogna andare a cercare nelle
posizioni alternative
✦ Le operazioni possono costare Ө(n) nel caso peggiore...
✦ ...ma hanno costo Ө(1) nel caso medio

✦ Due delle possibili tecniche:


✦ Liste di trabocco o memorizzazione esterna
✦ Indirizzamento aperto o memorizzazione interna

© Alberto Montresor 19
Tecniche di risoluzione delle collisioni

✦ Liste di trabocco (chaining) 0


✦ Gli elementi con lo stesso
valore hash h vengono
memorizzati in una lista k1 k4

✦ Si memorizza un puntatore
alla testa della lista nello
slot A[h] della tabella hash k5 k2 k6

✦ Operazioni:
k7 k3
✦ Insert:
inserimento in testa k8
✦ Lookup, Delete: m–1
richiedono di scandire la lista alla ricerca della chiave

© Alberto Montresor 20
rapporto tra il numero di chiavi memorizzate nella tabella e la dimensione della tabella stessa.
In altri termini, tabelle di dimensioni diverse presentano lo stesso tempo di ricerca qualora la
Liste di trabocco: complessità
percentuale di posizioni occupate sia la stessa. Siano:

n = numero di chiavi memorizzate nella tabella hash


m = dimensione della tabella hash
α = n/m (fattore di carico)
I(α) = numero medio di accessi alla tabella per la ricerca di una chiave non
presente nella tabella (ricerca con insuccesso)
S(α) = numero medio di accessi alla tabella per la ricerca di una chiave presente
nella tabella (ricerca con successo)

Le grandezze I(α) ed S(α) possono adeguatamente rappresentare la complessità media


✦ Analisi
delle del caso
operazioni pessimo:
lookup ✦ Analisi
(), insert() e remove(). Infatti, del caso
per inserire medio: non presente
un elemento
nella tabella occorre innanzitutto una ricerca con insuccesso,
✦ Tutte le chiavi sono collocate in
seguita dall’inserimento vero
✦ Dipende da come le chiavi
e proprio, mentre per cancellare un elemento presente nella tabella occorre una ricerca con
unica lista vengono distribuite
successo, seguita dalla cancellazione vera e propria. Pertanto, i tempi medi di inserzione e
✦ Insert: Ө(1)
cancellazione dipendono, a meno di costanti, da I(α) ✦ed Assumiamo
S(α). hashing
Search,I(α)
Le ✦grandezze Delete: Ө(n)sono state valutate matematicamente,
ed S(α) uniforme semplice
assumendo una distribu-
zione uniforme delle chiavi. Le funzioni ottenute al variare di α per i vari metodi di scansione
✦ Costo funzione di
sono, con buona approssimazione, le seguenti:
hashing f: θ(1)
S CANSIONE
© Alberto Montresor
α I(α) S(α) 21
Liste di trabocco: complessità

✦ Teorema:
✦ In tavola hash con concatenamento, una ricerca senza successo richiede un tempo
atteso Ө(1 + α)

✦ Dimostrazione:
✦ Una chiave non presente nella tabella può essere collocata in uno qualsiasi degli
m slot
✦ Una ricerca senza successo tocca tutte le chiavi nella lista corrispondente
✦ Tempo di hashing: 1 +
lunghezza attesa lista: α → Θ(1+α)
1
k1 k4

© Alberto Montresor 22
Liste di trabocco: complessità

✦ Teorema:
✦ In tavola hash con concatenamento, una ricerca con successo richiede un tempo
atteso di Ө(1 + α)
✦ Più precisamente: Ө(1 + α/2)

✦ Dimostrazione: idee chiave


✦ Si assuma che l'elemento cercato k sia uno qualsiasi degli n elementi presenti
nella tabella
✦ Il numero di elementi esaminati durante una ricerca con successo:
✦ 1 (l'elemento cercato) +
✦ in media, dovrò scandire metà della lista (di lunghezza attesa α)

© Alberto Montresor 23
Liste di trabocco: complessità

✦ Qual è il significato del fattore di carico:


✦ Influenza il costo computazionale delle operazioni sulle tabelle hash
✦ se n = O(m), α = O(1)
✦ quindi tutte le operazioni sono Ө(1)

© Alberto Montresor 24
Indirizzamento aperto

✦ Problema della gestione di collisioni tramite concatenamento


✦ Struttura dati complessa, con liste, puntatori, etc.

✦ Gestione alternativa: indirizzamento aperto


✦ Idea: memorizzare tutte le chiavi nella tabella stessa
✦ Ogni slot contiene una chiave oppure nil
✦ Inserimento:
✦ Se lo slot prescelto è utilizzato, si cerca uno slot “alternativo”
✦ Ricerca:
✦ Si cerca nello slot prescelto, e poi negli slot “alternativi” fino a quando non si
trova la chiave oppure nil

© Alberto Montresor 25
Indirizzamento aperto

✦ Ispezione: Uno slot esaminato durante una ricerca di chiave


✦ Sequenza di ispezione: La lista ordinata degli slot esaminati
✦ Funzione hash: estesa come
✦ H : U × [0 ... m-1] → [0 ... m-1]

✦ n. sequenza indice array


✦ La sequenza di ispezione { H(k, 0), H(k, 1), …, H(k, m–1) } è una permutazione
degli indici [0...m-1]
✦ Può essere necessario esaminare ogni slot nella tabella
✦ Non vogliamo esaminare ogni slot più di una volta

© Alberto Montresor 26
Indirizzamento aperto

✦ Cosa succede al fattore di carico α?


✦ Compreso fra 0 e 1
✦ La tabella può andare in overflow
✦ Inserimento in tabella piena
✦ Esistono tecniche di crescita/contrazione della tabella
✦ linear hashing

© Alberto Montresor 27
Tecniche di ispezione

✦ La situazione ideale prende il nome di hashing uniforme


✦ Ogni chiave ha la stessa probabilità di avere come sequenza di ispezione una
qualsiasi delle m! permutazioni di [0...m-1]
✦ Generalizzazione dell'hashing uniforme semplice

✦ Nella realtà:
✦ E' difficile implementare il vero uniform hashing
✦ Ci si accontenta di ottenere semplici permutazioni

✦ Tecniche diffuse:
✦ Ispezione lineare
✦ Ispezione quadratica
✦ Doppio hashing

© Alberto Montresor 28
Ispezione lineare

✦ Funzione: H(k, i) = (H(k)+h⋅i) mod m


chiave n. ispezione funzione hash base

✦ Il primo elemento determina l'intera sequenza


✦ H(k), H(k)+h, H(k)+2⋅h…, H(k)+(m-1)⋅h (tutti modulo m)
✦ Solo m sequenze di ispezione distinte sono possibili

✦ Problema: agglomerazione primaria (primary clustering)


✦ Lunghe sotto-sequenze occupate...
✦ ... che tendono a diventare più lunghe:
✦ uno slot vuoto preceduto da i slot pieni viene riempito con probabilità (i+1)/m
✦ I tempi medi di inserimento e cancellazione crescono

© Alberto Montresor 29
Ispezione quadratica

✦ Funzione: H(k, i) = (H(k) + h⋅i2) mod m

chiave n. ispezione funzione hash base

✦ Sequenza di ispezioni:
✦ L'ispezione iniziale è in H(k)
✦ Le ispezione successive hanno un offset che dipende da una funzione quadratica
nel numero di ispezione i
✦ Solo m sequenze di ispezione distinte sono possibili

✦ Problema: la sequenza così risultante non è una permutazione


✦ Problema: agglomerazione secondaria (secondary clustering)
✦ Se due chiavi hanno la stessa ispezione iniziale, le loro
sequenze sono identiche

© Alberto Montresor 30
Ispezione pseudo-casuale

✦ Funzione: H(k, i) = (H(k) + ri) mod m

chiave n. ispezione funzione hash base

✦ Sequenza di ispezioni:
✦ L'ispezione iniziale è in H(k)
✦ ri è l’i-esimo elemento restituito da un generatore di numeri casuali fra [0 ... m-1]
✦ Solo m sequenze di ispezione distinte sono possibili

✦ La sequenza così risultante è una permutazione


✦ Problema: agglomerazione secondaria (secondary clustering)
✦ Questo problema rimane

© Alberto Montresor 31
Doppio hashing

✦ Funzione: H(k, i) = (H(k) + i ⋅H’(k)) mod m

chiave n. ispezione funzioni hash base, ausiliaria

✦ Due funzioni ausiliarie:


✦ H fornisce la prima ispezione
✦ H’ fornisce l'offset delle successive ispezioni
✦ m2 sequenze di ispezione distinte sono possibili

✦ Nota: Per garantire una permutazione completa, H’(k) deve


essere relativamente primo con m
✦ Scegliere m = 2p e H’(k) deve restituire numeri dispari
✦ Scegliere m primo, e H’(k) deve restituire numeri minori di m

© Alberto Montresor 32
Cancellazione

✦ Non possiamo semplicemente sostituire la chiave che vogliamo cancellare con un


nil. Perché?
✦ Approccio
✦ Utilizziamo un speciale valore deleted al posto di nil per marcare uno slot come
vuoto dopo la cancellazione
✦ Ricerca: deleted trattati come slot pieni
✦ Inserimento: deleted trattati come slot vuoti

✦ Svantaggio: il tempo di ricerca non dipende più da α.


✦ Concatenamento più comune se si ammettono cancellazioni

© Alberto Montresor 33
Codice - Hashing doppio

H ASH
I TEM[ ] A % Tabella delle chiavi
I TEM[ ] V % Tabella dei valori
integer m % Dimensione della tabella
H ASH Hash(integer capacità)
H ASH t = new H ASH
t.m ← capacità
t.A ← new Item[0 . . . t.m − 1]
t.V ← new Item[0 . . . t.m − 1]
for i ← 0 to t.m − 1 do t.A[i] ← nil
return t
integer scan(I TEM k, boolean insert)
integer c ← m % Prima posizione deleted
integer i ← 0 % Numero di ispezione
integer j ← H(k) % Posizione attuale
while A[j] �= k and A[j] �= nil and i < m do
if A[j] = deleted and c = m then c ← j
© Alberto Montresor
j ← (j + H �
(k)) mod m 34
for i ← 0 to t.m − 1 do t.A[i] ← nil
Codice
return- Hashing
t doppio

integer scan(I TEM k, boolean insert)


integer c ← m % Prima posizione deleted
integer i ← 0 % Numero di ispezione
integer j ← H(k) % Posizione attuale
while A[j] �= k and A[j] �= nil and i < m do
if A[j] = deleted and c = m then c ← j
j ← (j + H � (k)) mod m
i←i+1
if insert and A[j] �= k and c < m then j = c
return j
I TEM lookup(I TEM k)
integer i ← scan(k, false)
if A[i] = k then
return V [i]
else
return nil

insert(I TEM k, I TEM v)


35
integer i ← scan(k, true)
© Alberto Montresor
if insert and A[j] �= k and c < m then j = c else
Codice - Hashing doppio % Errore: tabella hash pien
return j
I TEM lookup(I TEM k) remove(I TEM k)
integer i ← scan(k, false) integer i ← scan(k, false)
if A[i] = k then if A[i] = k then
return V [i] A[i] ← deleted
else
return nil

insert(I TEM k, I TEM v)


integer i ← scan(k, true)
if A[i] = nil or A[i] = deleted or A[i] = k then
A[i] ← k
V [i] ← v
else
% Errore: tabella hash piena

remove(I TEM k)
integer i ← scan(k, false)
if A[i] = k then
© Alberto Montresor 36
Indirizzamento aperto: Complessità hashing doppio

✦ Assunzioni
✦ Hashing uniforme
✦ Nessuna cancellazione
✦ Nella ricerca con successo, tutte le chiavi hanno la stessa probabilità di essere
cercate

✦ Analisi
✦ n chiavi inserite in una tabella di m slot
✦ n < m, ovvero il fattore di carico α < 1
✦ Analisi basata sul valore di α

© Alberto Montresor 37
Indirizzamento aperto: Complessità hashing doppio

✦ Il numero atteso di ispezioni I(α) per una ricerca senza successo è O(1/(1-α))
✦ Esempio: α=0.5, I(α)=2; α=0.9, I(α) =10
✦ A cosa tende queste valore per α → 1?

✦ Il numero atteso di ispezioni S(α) per una ricerca con successo è


O( - 1/α ln (1-α))
✦ Esempio: α=0.5, S(α) =1.387; α=0.9, S(α) =2.559

© Alberto Montresor 38
one uniforme delle chiavi. Le funzioni ottenute al variare di α per i vari metodi di scansion
no, con buona approssimazione,
Complessità - Riassunto le seguenti:

S CANSIONE α I(α) S(α)

(1 − α)2 + 1 1 − α/2
Lineare 0≤α<1
2(1 − α)2 1−α

1 1
Hashing doppio 0≤α<1 1−α − ln(1 − α)
α

Liste di trabocco α≥0 1+α 1 + α/2

© Alberto Montresor 39
O 7. TABELLE HASH 131

2
(1 − α) + 1 1 1 − α/2

2(1 − α) 2 1−α 1−α


5
Lineare

Q uadratica,
p seudocasuale,
hashing dop p io
4
Liste di trab occo

1
3 – ln (1 − α)
α

1+α

2
1 + α/2

0 0.2 0.4 0.6 0.8 1 α= n/m

Figura 7.3: Numero medio di accessi per ricerche in tabelle hash.


© Alberto Montresor 40
Ristrutturazione

✦ Usando la scansione interna, non è conveniente che α cresca troppo


✦ Sopra un soglia prefissata (tipicamente 0.5)
✦ Si alloca una nuova tabella di dimensione 2m
✦ Si reinseriscono tutte le chiavi presenti nella nuova tabella

✦ Risultato
✦ Fattore di carico dimezzato (tipicamente 0.25)
✦ Nessun elemento deleted

✦ Costi
✦ Costo O(m) per la ristrutturazione nel caso pessimo
✦ Costo ammortizzato costante (vedi dimostrazione per vettori)

© Alberto Montresor 41
Commenti finali

✦ Problemi con hashing


✦ Scarsa “locality of reference” (cache miss)
✦ Non è possibile ottenere le chiavi in ordine

✦ Implementazione
✦ HashMap in Java
✦ hash_map della Standard Template Library del C++

✦ Un’interessante estensione
✦ Distributed Hash Table (DHT)

© Alberto Montresor 42