Salta al contenuto
Note per Studenti Esercizio 19 · tabelle hash con separate chaining

Esercizio 19tabelle hash con separate chaining

In questa pagina 4

Testo.

Parte A (esercizio di lezione). Si consideri una tabella hash con N=11N = 11, h(k)=(3k+5) mod 11h(k) = (3k + 5) \bmod 11 e risoluzione delle collisioni tramite separate chaining. Far vedere la tabella dopo l'inserimento di entry con le seguenti chiavi: 12,44,13,88,23,94,11,39,2012, 44, 13, 88, 23, 94, 11, 39, 20.

Parte B (scritto del 07/08/2026, parte 1, esercizio 3, 4 punti). Si consideri una mappa implementata mediante una hash table di dimensione m=7m = 7, con gestione delle collisioni mediante liste concatenate. La funzione di hash è h(k)=k mod 7h(k) = k \bmod 7. Si inseriscano, nell'ordine indicato, le seguenti chiavi: 10,22,31,4,15,28,1710, 22, 31, 4, 15, 28, 17. (a) Disegnare il contenuto finale della hash table dopo tutti gli inserimenti. (b) Indicare quali chiavi vengono confrontate durante la ricerca della chiave 1717. (c) Qual è la complessità media e qual è la complessità al caso pessimo dell'operazione di ricerca in una hash table con concatenamento? Motivare brevemente la risposta. (d) Calcolare il load factor della hash table dopo tutti gli inserimenti.


Richiami

Con il separate chaining (vedi Tabelle hashTabella hash per implementare una mappa: funzione hash = hash code + compression function, bucket array, separate chaining; hash code per numeri e stringhe (polynomial, cyclic shift), division e MAD; load factor, complessità al caso pessimo Theta(n) e medio O(1+lambda), rehashing; esempio svolto con inserimenti e collisioni.Tabelle hash →, Mappe e dizionariADT mappa (chiavi distinte) con get, put, remove, keySet/values/entrySet; famiglia mappa/mappa ordinata/dizionario (multimappa); applicazioni; implementazioni semplici ma poco efficienti (lista, array indicizzato dalle chiavi); dizionario realizzato con una mappa di liste.Mappe e dizionari →) l'entry (k,v)(k, v) va nel bucket A[h(k)]A[h(k)], in coda alla lista. Il resto della divisione a mod Na \bmod N è il resto della divisione intera (come in 39 mod 7=439\bmod7=4: Notazione asintoticaDefinizioni di O, Omega, Theta e o piccolo con le costanti c ed n0; esempi con costanti esplicite; proprietà (polinomi, esponenziali, logaritmi, somme, implicazioni tra notazioni); sommatorie notevoli; terminologia (logaritmica, lineare, polinomiale, esponenziale).Notazione asintotica →; per i numeri interi Aritmetica binariaSomma e sottrazione in binario, overflow per senza segno (riporto) e per complemento a 2 (segni), flag del processore, moltiplicazione per somme e scorrimenti, algoritmo di Booth, divisione, shift logici e aritmetici.Aritmetica binaria →): si trova q=⌊a/N⌋q=\lfloor a/N\rfloor e si calcola a−qNa-qN. Si assume che in ogni lista le chiavi stiano nell'ordine di inserimento (se l'implementazione inserisce in testa, ogni lista risulta invertita: lo si dichiara).

Parte A

Si calcola h(k)h(k) per ciascuna chiave:

kk 12 44 13 88 23 94 11 39 20
3k+53k + 5 41 137 44 269 74 287 38 122 65
h(k)h(k) 8 5 0 5 8 1 5 1 10

(ad esempio 41=3⋅11+841 = 3 \cdot 11 + 8, 269=24⋅11+5269 = 24 \cdot 11 + 5.) Tabella finale:

Bucket Lista
0 1313
1 94→3994 \to 39
2, 3, 4 vuoti
5 44→88→1144 \to 88 \to 11
6, 7 vuoti
8 12→2312 \to 23
9 vuoto
10 2020

Collisioni nei bucket 11, 55 e 88. Con n=9n = 9 ed N=11N = 11 il load factor è λ=9/11≈0,82\lambda = 9/11 \approx 0{,}82. Lunghezze dei bucket 0,…,100,\dots,10: 1,2,0,0,0,3,0,0,2,0,11,2,0,0,0,3,0,0,2,0,1, somma 9=n9=n. Confronti per ritrovare ciascuna chiave (posizione nella lista): 13:113{:}1, 94:194{:}1, 39:239{:}2, 44:144{:}1, 88:288{:}2, 11:311{:}3, 12:112{:}1, 23:223{:}2, 20:120{:}1, in media 14/9≈1,5614/9\approx1{,}56 confronti per una ricerca con successo.

Parte B

Indici: 10 mod 7=310 \bmod 7 = 3; 22 mod 7=122 \bmod 7 = 1; 31 mod 7=331 \bmod 7 = 3; 4 mod 7=44 \bmod 7 = 4; 15 mod 7=115 \bmod 7 = 1; 28 mod 7=028 \bmod 7 = 0; 17 mod 7=317 \bmod 7 = 3. Passaggi: 10=7⋅1+310=7\cdot1+3, 22=7⋅3+122=7\cdot3+1, 31=7⋅4+331=7\cdot4+3, 4=7⋅0+44=7\cdot0+4, 15=7⋅2+115=7\cdot2+1, 28=7⋅4+028=7\cdot4+0, 17=7⋅2+317=7\cdot2+3. Con 77 chiavi in 77 bucket è quasi certo che ci siano collisioni: la probabilità che tutte finiscano in bucket diversi (hashing uniforme) è 7!77=5040823543≈0,006\frac{7!}{7^7}=\frac{5040}{823543}\approx0{,}006 (Calcolo combinatorio per la probabilitàNegli spazi uniformi bisogna contare: principio di moltiplicazione, disposizioni con ripetizione n^k, disposizioni semplici n!/(n−k)!, permutazioni n!, combinazioni (n su k); estrazioni con e senza reinserimento e distribuzione ipergeometrica.Calcolo combinatorio per la probabilità →).

(a) Contenuto finale (ordine di inserimento in ogni lista):

Bucket Lista
0 2828
1 22→1522 \to 15
2 vuoto
3 10→31→1710 \to 31 \to 17
4 44
5, 6 vuoti

Se invece ogni nuovo elemento fosse inserito in testa, le liste risulterebbero 15→2215 \to 22 nel bucket 11 e 17→31→1017 \to 31 \to 10 nel bucket 33.

(b) Ricerca di 1717: h(17)=3h(17) = 3; si scandisce la lista del bucket 33 e si confrontano nell'ordine le chiavi 1010, 3131, 1717 (la terza trova la chiave). Con l'inserimento in testa si confronterebbe solo 1717. Le chiavi negli altri bucket non vengono toccate.

(c) Complessità. Detto λ=n/N\lambda = n/N il load factor:

  • caso medio: Θ(1+λ)\Theta(1 + \lambda) sotto l'ipotesi di hashing uniforme: costo costante per calcolare h(k)h(k) e la scansione di un bucket di lunghezza media λ\lambda. Se la tabella cresce in modo da mantenere λ=O(1)\lambda = O(1) si ha Θ(1)\Theta(1);
  • caso pessimo: Θ(n)\Theta(n): tutte le nn chiavi possono finire nello stesso bucket e la chiave cercata può essere in fondo alla lista o assente.

Il valore medio λ\lambda per la lunghezza di un bucket è un Valore attesoIl valore atteso E[X] = Σ x p_X(x) è la media dei valori di X pesata con le loro probabilità (esiste se la serie converge assolutamente); per una funzione g vale E[g(X)] = Σ g(x) p_X(x) senza trovare la legge di g(X), ed E è lineare: E[aX + bY + c] = aE[X] + bE[Y] + c.Valore atteso →: ogni chiave cade in un dato bucket con probabilità 1/N1/N, quindi le nn chiavi producono in media n/Nn/N chiavi per bucket. Qui le lunghezze effettive sono 1,2,0,3,1,0,01,2,0,3,1,0,0 (somma 77), con media 11.

(d) Load factor: λ=n/N=7/7=1\lambda = n/N = 7/7 = 1.

(Entrambe le tabelle sono state verificate con un programma.)

Errori comuni

  • Applicare hh senza ridurre modulo NN (si ottengono indici fuori dalla tabella) o sbagliare il resto (controllare con 3k+5−11q3k + 5 - 11q).
  • Confrontare nella ricerca anche chiavi di altri bucket: si guarda solo il bucket h(k)h(k).
  • Dire che la ricerca è O(1)O(1) al caso pessimo: lo è in media.
  • Definire il load factor come N/nN/n (rovesciato) o come lunghezza massima del bucket: è il rapporto entry/bucket, cioè la lunghezza media.

Versione ripasso

Testo. (A) N=11N = 11, h(k)=(3k+5) mod 11h(k) = (3k+5) \bmod 11, chaining, chiavi 12,44,13,88,23,94,11,39,2012,44,13,88,23,94,11,39,20. (B) m=7m = 7, h(k)=k mod 7h(k) = k \bmod 7, chiavi 10,22,31,4,15,28,1710,22,31,4,15,28,17: (a) tabella, (b) chiavi confrontate cercando 1717, (c) complessità media e pessima della ricerca, (d) load factor.

Teoria collegata