Una tabella hash è una struttura dati che associa chiavi uniche a valori. Immagina un grande archivio dove, invece di cercare tutto riga per riga, usi una “funzione hash” per trovare immediatamente la posizione del dato che ti interessa.
Cos’è una tabella hash?
È una struttura dati che mappa (nel senso che collega, unisce tra loro) una chiave a un valore.
Es: numero di telefono (valore) associato a un nome (chiave).
Perché usare una tabella hash?
- Accesso rapidissimo ai dati tramite chiave
- Ottima per cercare, inserire o cancellare elementi in modo efficiente
- Usata per implementare dizionari, rubrica, cache e molto altro
Come funziona la tabella hash
- Tu dai una chiave (es. “Marco”)
- La tabella applica una funzione hash (una specie di trasformazione) alla chiave, che genera un indice
- Usa quell’indice per trovare la posizione dove è memorizzato il valore (es. l’età di Marco)
La classe HashMap
in Java
In Java, la tabella hash si usa tramite la classe HashMap
(fa parte del package java.util
).
Caratteristiche:
- Permette di mappare chiavi (di tipo generico
K
) a valori (di tipoV
) - Non mantiene l’ordine degli elementi
- Supporta chiavi e valori
null
- Accesso e inserimento in media molto veloci (complessità O(1))
Sintassi base
HashMap<K, V> nomeMappa = new HashMap<>();
K
= tipo chiave (es. String)V
= tipo valore (es. Integer)
Operazioni principali
Operazione | Metodo | Descrizione |
---|---|---|
Inserire o aggiornare | put(K chiave, V valore) | Aggiunge o sovrascrive valore |
Ottenere valore | get(K chiave) | Restituisce valore associato |
Verificare chiave | containsKey(K chiave) | Controlla se la chiave esiste |
Rimuovere coppia | remove(K chiave) | Elimina chiave e valore |
Ottenere dimensione | size() | Numero coppie chiave-valore |
Ottenere chiavi | keySet() | Set di tutte le chiavi |
Esempio pratico minimal
Hashtable senza collisioni
public class HashTable { String[] keys = new String[10]; int[] vals = new int[10]; int hash(String k) { return Math.abs(k.hashCode()) % keys.length; } void put(String k, int v) { int i = hash(k); keys[i] = k; vals[i] = v; } Integer get(String k) { int i = hash(k); return (keys[i] != null && keys[i].equals(k)) ? vals[i] : null; } public static void main(String[] args) { HashTable ht = new HashTable(); ht.put("A", 1); ht.put("B", 2); System.out.println(ht.get("A")); // 1 System.out.println(ht.get("B")); // 2 System.out.println(ht.get("C")); // null } }
Esempio più avanzato
import java.util.HashMap;
public class EsempioHashMap {
public static void main(String[] args) {
HashMap<String, Integer> etàPersone = new HashMap<>();
etàPersone.put("Alice", 28);
etàPersone.put("Bob", 35);
System.out.println("Età di Alice: " + etàPersone.get("Alice"));
System.out.println("Chiavi nella mappa: " + etàPersone.keySet());
}
}
Quando usare una HashMap
- Quando ti serve cercare velocemente dati tramite una chiave
- Quando non importa l’ordine degli elementi
- Quando vuoi una struttura facile da usare e performante per associazioni chiave/valore
Esempio minimal
Ecco un esempio minimale e funzionale di HashMap
in Java, che mostra come aggiungere, leggere e stampare valori associati a chiavi:
import java.util.HashMap;
public class HashMapMinimale {
public static void main(String[] args) {
HashMap<String, Integer> mappa = new HashMap<>();
mappa.put("Alice", 25);
mappa.put("Bob", 30);
System.out.println("Alice ha " + mappa.get("Alice") + " anni.");
System.out.println("Bob ha " + mappa.get("Bob") + " anni.");
}
}
Compila e avvia così:
javac HashMapMinimale.java
java HashMapMinimale
Output:
Alice ha 25 anni.
Bob ha 30 anni.
In Java: HashMap
La classe più usata è HashMap
, che fa proprio questo:
HashMap<K, V>
doveK
è tipo chiave eV
è tipo valore.
Esempio
import java.util.HashMap;
public class HashMapDemo {
public static void main(String[] args) {
HashMap<String, Integer> mappa = new HashMap<>();
// aggiungi coppie chiave-valore
mappa.put("Alice", 25);
mappa.put("Marco", 30);
mappa.put("Luca", 28);
// prendi un valore da una chiave
System.out.println("Età di Marco: " + mappa.get("Marco"));
// verifica se una chiave esiste
if (mappa.containsKey("Alice")) {
System.out.println("Alice è nella mappa");
}
// rimuovi una coppia
mappa.remove("Luca");
// stampa tutte le chiavi e valori
for (String nome : mappa.keySet()) {
System.out.println(nome + " ha " + mappa.get(nome) + " anni.");
}
}
}
Metodi utili di HashMap
Metodo | Descrizione |
---|---|
put(K chiave, V valore) | Aggiunge o aggiorna una coppia |
get(K chiave) | Restituisce valore associato |
remove(K chiave) | Rimuove coppia per chiave |
containsKey(K chiave) | Verifica esistenza chiave |
size() | Numero coppie presenti |
clear() | Pulisce tutta la mappa |
keySet() | Insieme di tutte le chiavi |
values() | Collezione di tutti i valori |
HashMap con oggetti personalizzati
Puoi anche usare anche oggetti come chiave o valore, ma se usi oggetti come chiavi, devi implementare hashCode()
e equals()
nella classe chiave, altrimenti rischi problemi.
Assolutamente! Quando usi oggetti personalizzati come chiavi in una HashMap (o in qualsiasi tabella hash in Java), devi implementare correttamente i metodi hashCode()
e equals()
nella classe chiave. Questo perché:
hashCode()
determina in quale “secchio” (bucket) va messa la chiave nella tabella hashequals()
serve per distinguere due oggetti diversi ma con stesso hash (collisione)
Se non li implementi, due oggetti con stessi valori potrebbero non essere riconosciuti come uguali, causando problemi nella ricerca o inserimento. Supponiamo di avere una classe semplice Punto
(x,y), che vogliamo usare come chiave.
Senza hashCode()
e equals()
(NON funziona bene):
import java.util.HashMap;
class Punto {
int x, y;
Punto(int x, int y) {
this.x = x; this.y = y;
}
}
public class EsempioMappa {
public static void main(String[] args) {
HashMap<Punto, String> mappa = new HashMap<>();
Punto p1 = new Punto(1, 2);
Punto p2 = new Punto(1, 2);
mappa.put(p1, "Primo punto");
// p2 ha gli stessi valori di p1, ma è un oggetto diverso
System.out.println(mappa.get(p2)); // stampa null, NON trova p2!
}
}
Con hashCode()
e equals()
corretti (FUNZIONA):
import java.util.HashMap;
import java.util.Objects;
class Punto {
int x, y;
Punto(int x, int y) {
this.x = x; this.y = y;
}
@Override
public boolean equals(Object o) {
if (this == o) return true; // stessa istanza
if (o == null || getClass() != o.getClass()) return false; // classe diversa
Punto punto = (Punto) o;
return x == punto.x && y == punto.y; // valori uguali
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
public class EsempioMappa {
public static void main(String[] args) {
HashMap<Punto, String> mappa = new HashMap<>();
Punto p1 = new Punto(1, 2);
Punto p2 = new Punto(1, 2);
mappa.put(p1, "Primo punto");
System.out.println(mappa.get(p2)); // stampa "Primo punto" — funziona!
}
}
In questo caso:
hashCode()
restituisce un codice (int) basato sux
ey
equals()
dice se due oggettiPunto
sono uguali confrontandox
ey
- Ora
p1
ep2
sono considerati uguali come chiave nellaHashMap