A.A. 2006/07
Tabelle
Operazioni:
insert(elem e, chiave k)
aggiunge ad S una nuova coppia (e, k)
delete(elem e, chiave k)
cancella da S la coppia con chaive k
search(chiave k)
se la chiave k è presente in s restituisce l’elemento
e ad esso associato altrimenti restituisce null
Operazioni su tabelle
Ricerca su tabelle
2 Tabelle Hash
Parte I
Universo
0
9 6
4 7 2
1
3
K 2
chiavi effettive 3 5
5
8
8
Direct-Address-Search(T , k) Direct-Address-Insert(T , x)
return T [k] T [key [x]] ← x
Direct-Address-Delete(T , x)
T [key [x]] ← nil
Inconvenienti
Inconvenienti
Universo
0
9 6
4 7 2
1
3
K 2
chiavi effettive 3 5
5
8
8
= spazio inutilizzato
Fattore di carico
Parte II
Tabelle Hash
Tabelle Hash
h : U 7→ [0, 1, . . . m − 1]
Tabelle Hash
Contro:
perdiamo la corrispondenza tra chiavi e posizioni in tabella
le tabelle hash possono soffrire del fenomeno delle collisioni
Collisioni
k1 6= k2 =⇒ h(k1 ) 6= h(k2 )
Deve essere |U| ≤ m
Sia P(k) la probabilità che sia estratta una chiave k tale che
h(k) = j, allora
X 1
P(k) = per j = 0, . . . , m − 1
m
k:h(k)=j
h(k) = k mod m
Semplice e veloce, ma occorre evitare certi valori di m; m non
dovrebbe essere una potenza di 2
k1 k4
k5 k2 k7
k3
k8 k6
Chained-Hash-Search(T , k)
ricerca un elemento con chiave k nella lista T [h(k)]
Chained-Hash-Insert(T , x)
inserisci x in testa alla lista T [h(key [x])]
Chained-Hash-Delete(T , x)
cancella x dalla lista T [h(key [x])]
Chained-Hash-Search(T , k)
il tempo di esecuzione è, nel caso peggiore, proporzionale
alla lunghezza della lista
Chained-Hash-Insert(T , x)
il tempo di esecuzione nel caso peggiore è O(1)
Chained-Hash-Delete(T , x)
se si usano liste bidirezionali, può richiedere un tempo O(1)
con liste semplici, richiede lo stesso tempo della ricerca
Ipotesi:
Proof:
Occorre O(1) tempo per il calcolo della funzione h(k); inoltre
si deve scorrere completamente la lista T [h(k)].
n n n
1X i −1 1 X X i − 1
(1 + )= 1+ =
n m n m
i=1 i=1 i=1
n n−1
1 1 X 1 1 X
n+ (i − 1) = n + i) =
n m n m
i=1 i=0
1 1 n(n − 1) n−1
n+ =1+ =
n m 2 2m
α 1
1+ − = Θ(1 + α)
2 2m
Indirizzamento Aperto
Indirizzamento Aperto
Indirizzamento Aperto
h : U × {0, 1, . . . , m − 1} → {0, 1, . . . , m − 1}
Operazione di Inserimento
Hash-Insert(T , k)
i ←0
repeat
j ← h(k, i)
if T [j] = nil or T [j] = deleted
then T [j] = k return j
else i ← i + 1
until i = m
error “overflow sulla tabella hash”
Operazione di Ricerca
Hash-Search(T , k)
i ←0
repeat
j ← h(k, i)
if T [j] = k return j
i ←i +1
until T [j] = nil or i = m
return nil
Operazione di Cancellazione
Il problema della cancellazione di un elemento in una tabella hash
ad indirizzamento aperto è appena un pò più complesso
Cosı̀ facendo i tempi di ricerca non dipendo più solo dal fattore di
carico α; l’uso di liste di collisione è più comune se si ammettono
cancellazioni frequenti
Di Berardini, Merelli Algoritmi e Strutture Dati
Liste di collisione
Liste di collisione: analisi
Tabelle Hash
Indirizzamento aperto
Indirizzamento aperto: analisi
Fact
∞
X ∞
X
i · Pr {X = i} = Pr {X ≥ i}
i=0 i=1
Se denotiamo con
allora ∞ ∞
X X
i · pi = i · qi
i=0 i=1
∞ ∞ ∞ ∞
X X X
i
X 1
1+ i · pi = 1 + qi ≤ 1 + α = αi =
i=0 i=1 i=1 i=0
1−α
Inserimento
Inserimento – dimostrazione
1 1 1 m
= = =
(1 − αi ) (1 − i/m) (m − i/m) (m − i)
Eseguendo la media su tutte le n chiavi nella tabella hash si ottiene
un numero medio di accessi
n−1 n−1 n−1
1 X m m X 1 1 X 1
= =
n i=0 (m − i) n i=0 (m − i) α i=0 (m − i)
n−1 m
X 1 X 1
= (ponendo k = m − i)
(m − i) k
i=0 k=m−n+1
m Z m−n
X 1 1 m 1
≤ dx = ln m−ln(m−n) = ln( ) = ln( )
k n x m−n 1−α
k=m−n+1
Parte III
Scansione Lineare
Scansione Lineare
Scansione Lineare
4
h0 (k) #acc
5
0 6
6 1 5
7 2 4
8 3 3
9 4 2
posizioni occupate 5–9 1
9
1 X 1
#acc[h0 (k) = i] = · 25 = 2.5
10 10
i=0
5
h0 (k) #acc
6 pari 2
7 dispari 1
8
9
1
((2 · 5) + (1 · 5)) = 1.5
10
posizioni occupate
Inoltre ...
Scansione Quadratica
Scansione Quadratica
Un esempio:
dove, c1 = c2 = 1
h(k, 0) = h0 (k),
h(k, 1) = h0 (k) + 1 + 1 = h0 (k) + 2,
h(k, 2) = h0 (k) + 2 + 4 = h0 (k) + 6,
h(k, 3) = h0 (k) + 3 + 9 = h0 (k) + 12,
h(k, 4) = h0 (k) + 4 + 16 = h0 (k) + 20
Scansione Quadratica
Hashing Doppio
h(k, i) = h1 (k) + ih2 (k) mod m
Hashing Doppio
0
k = 14
1 79
2 h1(k) = k mod 13 = 1
3 h2(k) = 1 + (k mod 11) = 4
4 69
5 98
6 h(k,0) = 1 mod 13 = 1
7 h(k,1) = (1 + 1·4) mod 13 = 5
8
9
10
11 50
12
Hashing Doppio
0
k = 14
1 79
2 h1(k) = k mod 13 = 1
3 h2(k) = 1 + (k mod 11) = 4
4 69
5 98
6 h(k,0) = 1 mod 13 = 1
7 h(k,1) = (1 + 1·4) mod 13 = 5
8 h(k,1) = (1 + 2·4) mod 13 = 9
9 14
10
11 50
12
Hashing Doppio
La prima posizione esaminata è T [h1 (k)] mod m; ogni posizione
esaminata successivamente è distanziata dalla precedente di una
quantità h2 (k) mod m
Hashing Doppio
0
K = 14
1 79
2 h1(k) = k mod 13 = 1
3 h2(k) = 1 + (k mod 10) = 5
4 69
5 98 h2(k) non è primo con m
6 15
7 h(k,0) = (1 + 0·5) mod 10 = 1
8 h(k,1) = (1 + 1·5) mod 10 = 6
9 h(k,2) = (1 + 2·5) mod 10 = 1
h(k,3) = (1 + 3·5) mod 10 = 6
h(k,4) = (1 + 4·5) mod 10 = 1
....
Hashing Doppio