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