Sono d'accordo con:
- la complessità generale ammortizzata di O (1)
- una cattiva
hashCode()implementazione potrebbe comportare più collisioni, il che significa che nel caso peggiore ogni oggetto va nello stesso bucket, quindi O ( N ) se ogni bucket è supportato da a List.
- da Java 8,
HashMapsostituisce dinamicamente i Nodi (elenco collegato) utilizzati in ogni bucket con TreeNodes (albero rosso-nero quando un elenco diventa più grande di 8 elementi) con conseguenti prestazioni peggiori di O ( logN ).
Ma questo NON è la verità se vogliamo essere precisi al 100%. L'implementazione hashCode()e il tipo di chiave Object(immutabile / memorizzata nella cache o essendo una raccolta) potrebbe anche influire sulla complessità reale in termini rigorosi.
Supponiamo che i seguenti tre casi:
HashMap<Integer, V>
HashMap<String, V>
HashMap<List<E>, V>
Hanno la stessa complessità? Bene, la complessità ammortizzata della prima è, come previsto, O (1). Ma, per il resto, dobbiamo anche calcolare hashCode()l'elemento di ricerca, il che significa che potremmo dover attraversare matrici ed elenchi nel nostro algoritmo.
Supponiamo che la dimensione di tutti gli array / elenchi sopra sia k . Quindi, HashMap<String, V>e HashMap<List<E>, V>avrà la complessità ammortizzata O (k) e allo stesso modo, il caso peggiore di O ( k + logN ) in Java8.
* Si noti che l'utilizzo di una Stringchiave è un caso più complesso, poiché è immutabile e Java memorizza nella cache il risultato hashCode()in una variabile privata hash, quindi viene calcolata una sola volta.
/** Cache the hash code for the string */
private int hash; // Default to 0
Ma quanto sopra ha anche il suo caso peggiore, poiché l' String.hashCode()implementazione di Java sta verificando se hash == 0prima dell'informatica hashCode. Ma ehi, ci sono stringhe non vuote che producono uno hashcodezero, come "f5a5a608", vedi qui , nel qual caso la memoizzazione potrebbe non essere utile.