Panoramica della tabella hash semplice
Come aggiornamento, una tabella hash è un modo per memorizzare un valore in una chiave specifica in una struttura di dati. Ad esempio, potrei memorizzare il valore "a"
sotto la chiave 1
e poi recuperarlo cercando la chiave 1
nella tabella hash.
L'esempio più semplice di una tabella hash che mi viene in mente dalla parte superiore della mia testa è una tabella hash che può solo memorizzare numeri interi, dove la chiave per la voce della tabella hash è anche il valore che viene archiviato. Supponiamo che la tua tabella abbia dimensioni 8 ed è sostanzialmente un array in memoria:
---------------------------------
| | | | | | | | |
---------------------------------
0 1 2 3 4 5 6 7
Funzione hash
Le funzioni hash ti danno un indice su dove archiviare il tuo valore. Una funzione hash piuttosto semplice per questa tabella sarebbe quella di aggiungere 1 al valore che si desidera memorizzare e quindi modificarlo di 8 (la dimensione della tabella). In altre parole, la tua funzione hash è (n+1)%8
, dov'è n
il numero intero che vuoi memorizzare.
inserti
Se vuoi inserire un valore in questa tabella hash, chiami la tua funzione hash (in questo caso (n+1)%8
) sul valore che vuoi inserire per darti un indice. Ad esempio, se vogliamo inserire 14, chiamiamo (14 + 1) % 8
e otteniamo l'indice 7
, quindi inseriamo il valore nell'indice 7
.
---------------------------------
| | | | | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Allo stesso modo, possiamo inserire 33, 82 e 191 in questo modo:
---------------------------------
|191| |33 |82 | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
collisioni
Ma cosa succede se proviamo a inserire qualcosa che si scontrerebbe con una voce? 2 dovrebbe andare in indice 3
, ma è preso da 82. Ci sono molti modi per risolvere questo problema, il più semplice è chiamare ripetutamente la nostra funzione di hash finché non troviamo uno spazio vuoto.
Quindi la logica è la seguente:
- (2 + 1)% 8 = 3
- L'indice 3 è pieno
- Ricollega 3 alla nostra funzione hash. ( 3 + 1)% 8 = 4 , che è vuoto.
- Posiziona il nostro valore nell'indice 4 .
Ora la tabella hash è simile a questa, con il valore 2 memorizzato nell'indice 4
.
---------------------------------
|191| |33 |82 |2 | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
L'aspetto negativo di questa soluzione è che molto presto, il nostro tavolo si riempirà! Se sai che le dimensioni dei tuoi dati sono limitate, questo non dovrebbe costituire un problema se la tua tabella è abbastanza grande da contenere tutti i possibili valori. Se vuoi essere in grado di trattenerne di più, puoi gestire le collisioni in modo diverso. Torniamo al punto in cui eravamo prima di inserire 2.
---------------------------------
|191| |33 |82 | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Se ricordi, (2+1)%8
ci dà un indice 3
, che è preso. Se non si desidera riempire la tabella hash, è possibile utilizzare ciascun indice di tabella come elenco collegato e aggiungerlo all'elenco in tale indice. Quindi, invece di chiamare nuovamente la funzione hash, aggiungeremo semplicemente all'elenco in indice 3
:
-----
| 2 |
---------------------------------
|191| |33 |82 | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Questo elenco può quindi crescere fino a quando la memoria lo permetterà. Posso inserire 18, e sarà solo aggiunto a 2:
-----
|18 |
-----
| 2 |
---------------------------------
|191| |33 |82 | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Ricerche
La ricerca dei valori nella tabella hash è rapida, dato che la tabella hash ha dimensioni piuttosto grandi. Chiama semplicemente la tua funzione hash e ottieni l'indice. Diciamo che vuoi vedere se 82 è nella tua tabella. La funzione di ricerca chiamerebbe (82+1)%8
= 3
, e guarderebbe l'elemento in indice 3
e lo restituirebbe per te. Se hai cercato 16, la funzione di ricerca cercherebbe nell'indice 1
e vedrà che non esiste.
Anche le ricerche devono gestire le collisioni!
Se si tenta di cercare il valore 2, la tabella hash dovrebbe utilizzare la stessa logica di collisione utilizzata per l'archiviazione dei dati e per il recupero dei dati. A seconda del modo in cui funziona la tua tabella di hash, dovrai sempre ripetere l'hashing della chiave fino a trovare la voce che stai cercando (o trovare uno spazio vuoto), oppure scorrere l'elenco collegato fino a quando non trovi l'elemento (o arrivato alla fine della lista)
Sommario
Pertanto, le tabelle hash sono un buon modo per archiviare e accedere rapidamente a coppie chiave-valore. In questo esempio abbiamo usato la stessa chiave del valore, ma nelle tabelle hash del mondo reale le chiavi non sono così limitate. Le funzioni di hash funzioneranno sulle chiavi per generare un indice, quindi la chiave / valore può essere memorizzata in quell'indice. Le tabelle hash non sono pensate per essere ripetute, anche se è possibile farlo. Come puoi vedere, le tabelle di hash possono avere molti spazi vuoti e iterarli attraverso di loro sarebbe una perdita di tempo. Anche se la tabella hash ha una logica per saltare le ricerche di spazi vuoti nel suo iteratore, sarebbe più adatto usare una struttura di dati progettata per gli iteratori, come gli elenchi collegati.