Panoramica della tabella hash semplice
Come aggiornamento, una tabella hash è un modo per memorizzare un valore sotto una chiave specifica in una struttura dati. Ad esempio, potrei memorizzare il valore "a"
sotto la chiave 1
, e successivamente recuperarlo cercando la chiave 1
nella tabella hash.
L'esempio più semplice di una tabella di hash che posso pensare in cima alla mia testa è una tabella hash che può solo memorizzare interi, dove la chiave per la voce della tabella hash è anche il valore che viene memorizzato. Diciamo che la tua tabella è di dimensione 8, ed è fondamentalmente una matrice in memoria:
---------------------------------
| | | | | | | | |
---------------------------------
0 1 2 3 4 5 6 7
Funzione hash
Le funzioni di hash ti danno un indice su dove memorizzare il tuo valore. Una semplice funzione di hash per questa tabella sarebbe quella di aggiungere 1 al valore che si desidera memorizzare, quindi mod it per 8 (la dimensione della tabella). In altre parole, la tua funzione di hash è (n+1)%8
, dove n
è il numero intero che desideri memorizzare.
Inserti
Se vuoi inserire un valore in questa tabella hash, chiami la tua funzione di hash (in questo caso (n+1)%8
) sul valore che vuoi inserire per darti un indice. Ad esempio, se vogliamo inserire 14, chiameremmo (14 + 1) % 8
e ottieni indice 7
, quindi inseriremo 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 colliderebbe con una voce? 2 dovrebbe andare nell'indice 3
, ma è preso da 82. Ci sono molti modi per risolvere questo problema, il più semplice è chiamare la nostra funzione di hash ancora e ancora ripetutamente finché non troviamo uno spazio vuoto.
Quindi la logica è la seguente:
- (2 + 1)% 8 = 3
- Indice 3 è completo
- Spina 3 nella nostra funzione di hash. ( 3 + 1)% 8 = 4 , che è vuoto.
- Inserisci il nostro valore nell'indice 4 .
Ora la tabella hash appare così, con il valore 2 memorizzato all'indice 4
.
---------------------------------
|191| |33 |82 |2 | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Il lato negativo di questa soluzione è che presto, il nostro tavolo si riempirà! Se sai che la dimensione dei tuoi dati è limitata, questo non dovrebbe essere un problema se la tua tabella è abbastanza grande da contenere tutti i valori possibili. Se vuoi essere in grado di contenere 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à indice 3
, che è preso. Se non si desidera riempire la tabella hash, è possibile utilizzare ciascun indice tabella come elenco collegato e aggiungerlo all'elenco in tale indice. Quindi, invece di chiamare di nuovo la funzione di hash, semplicemente aggiungeremo l'elenco all'indice 3
:
-----
| 2 |
---------------------------------
|191| |33 |82 | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Questo elenco può quindi aumentare quanto la memoria lo consente. Posso inserire 18 e sarà aggiunto a 2:
-----
|18 |
-----
| 2 |
---------------------------------
|191| |33 |82 | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Ricerche
I valori di ricerca nella tabella hash sono veloci, dato che la tabella hash ha dimensioni piuttosto grandi. Basta chiamare la funzione hash e ottenere l'indice. Diciamo che vuoi vedere se 82 è nel tuo tavolo. La funzione di ricerca chiamerebbe (82+1)%8
= 3
e guarda l'elemento nell'indice 3
e lo restituisce per te. Se hai cercato 16, la funzione di ricerca sembrerebbe nell'indice 1
e vedrai che non esiste.
Le ricerche devono anche gestire le collisioni!
Se si tenta di cercare il valore 2, la tabella hash dovrebbe utilizzare la stessa logica di collisione utilizzata per la memorizzazione dei dati come per il recupero dei dati. A seconda del modo in cui il tuo hash table funziona, dovresti o hash il tasto più e più volte fino a trovare la voce che stai cercando (o trovare uno spazio vuoto), o continueresti a scorrere l'elenco collegato fino a quando non hai trovato l'elemento (o arrivato alla fine della lista)
Sommario
Quindi, 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 di hash del mondo reale le chiavi non sono così limitate. Le funzioni di hash funzioneranno sulle chiavi per generare un indice e quindi la chiave / il valore può essere memorizzato in quell'indice. Le tabelle hash non sono pensate per essere ripetute, anche se è possibile farlo. Come puoi vedere, le tabelle hash possono avere un sacco di spazi vuoti e scorrere tra loro sarebbe una perdita di tempo. Anche se la tabella hash ha la logica per ignorare le ricerche di spazio vuoto nel suo iteratore, ti conviene utilizzare una struttura dati progettata per iteratori, come gli elenchi collegati.