Middle
Kaip yra sukurta ir organizuota duomenų struktūra HashMap Java?
sobes.tech AI
Atsakymas iš AI
HashMap Java kalba yra pagrįsta maišos funkcijos principais. Ji saugo poras "raktas-reikšmė".
Vidinė struktūra:
- Dėžučių masyvas. Kiekviena dėžutė yra susijusi sąrašas (arba medis nuo Java 8, kai kolizijos yra didelės).
- Pridedant elementą (
put):- Apskaičiuojamas rakto hash kodas (
key.hashCode()). - Hash kodas modifikuojamas geresniam paskirstymui (
hash). - Naudojant modifikuotą hash ir dėžučių masyvo dydį, apskaičiuojamas dėžutės indeksas (
хеш & (masyvo_dydis - 1)). - Elementas (poros "raktas-reikšmė" objektas
Node) įdedamas į šią dėžutę. Jei dėžutė jau turi elementų, naujas elementas pridedamas prie susietojo sąrašo arba medžio pradžios. - Pridedant tikrinama, ar yra raktas: naudojamas
equals()metodas rakto palyginimui dėžutėje. Jei raktas rastas, reikšmė atnaujinama.
- Apskaičiuojamas rakto hash kodas (
- Gaunant elementą (
get):- Taip pat apskaičiuojamas dėžutės indeksas pagal raktą.
- Dėžutėje ieškoma elemento pagal raktą, naudojant
hashCode()irequals()metodus. - Grąžinama susieta reikšmė.
Organizacija:
- Kolizijos: Jei keli raktai turi tą patį hash kodą ir patenka į tą patį dėžutę, elementai saugomi susietame sąraše. Nuo Java 8, kai dėžutės elementų skaičius viršija slenkstį (dažniausiai 8), susietas sąrašas paverčiamas medžiu greitesniam paieškai (O(log n) vietoj O(n)).
- Perdarymas: Kai elementų skaičius viršija "įkrovimo lygį" (
load factor * capacity), HashMap padidina vidinio masyvo dydį (dažniausiai dvigubai) ir perheshuoja visus elementus. Tai brangi operacija (O(n)). - Parametrai:
capacity: Pradinis dėžučių masyvo dydis (numatytasis 16).load factor: Įkrovimo slenkstis (numatytasis 0.75). Nustato, kada įvyks perdarymas.
Kodėl svarbūs hashCode() ir equals():
- Teisingas HashMap veikimas priklauso nuo šių metodų teisingos įgyvendinimo.
- Jei
equals()grąžinatruedviems objektams, tadahashCode()turi grąžinti tą patį reikšmę. - Netinkama įgyvendinimas gali sukelti tai, kad elementai nebus rasti (
getgrąžinsnull), nors jie buvo pridėti.
Node struktūros pavyzdys:
// Tik vidiniam naudojimui
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
HashMap užtikrina greitą (vidutiniškai O(1)) elementų pridėjimą, gavimą ir ištrynimą, kai hash'ai paskirstyti tolygiai. Blogiausiu atveju (stiprios kolizijos) operacija gali tapti O(n) arba O(log n) su medžiais.