Middle
Jak je strukturována a organizována datová struktura HashMap v Javě?
sobes.tech AI
Odpověď od AI
HashMap v Javě je založen na principech hašování. Ukládá páry "klíč-hodnota".
Vnitřní struktura:
- Pole košů (kontejnerů). Každý koš je spojový seznam (nebo strom, od Java 8, pokud je mnoho kolizí).
- Při přidání prvku (
put):- Vypočítá se hash kód klíče (
key.hashCode()). - Hash kód je upraven pro lepší rozložení (
hash). - Pomocí upraveného hashe a velikosti pole se vypočítá index koše (
hash & (array_size - 1)). - Prvek (pár "klíč-hodnota" jako objekt
Node) je umístěn do tohoto koše. Pokud koš již obsahuje prvky, nový prvek se přidá na začátek spojového seznamu nebo stromu. - Při přidání se kontroluje existence klíče: používá se metoda
equals()pro porovnání klíčů v koši. Pokud je klíč nalezen, hodnota je aktualizována.
- Vypočítá se hash kód klíče (
- Při získání prvku (
get):- Index koše se vypočítá podle klíče.
- Uvnitř koše se hledá prvek podle klíče pomocí metod
hashCode()aequals(). - Vrací se spojená hodnota.
Organizace:
- Kolize: Pokud několik klíčů má stejný hash kód a spadnou do jednoho koše, jsou uloženy jako spojový seznam. Od Java 8, pokud počet prvků v koši přesáhne práh (obvykle 8), spojový seznam se převede na strom pro rychlejší hledání (O(log n) místo O(n)).
- Změna velikosti: Když počet prvků přesáhne "práh načtení" (
load factor * capacity), HashMap zvětší velikost vnitřního pole (obvykle zdvojnásobí) a přehashuje všechny prvky. Tato operace je nákladná (O(n)). - Parametry:
capacity: Počáteční velikost pole (výchozí 16).load factor: Práh načtení (výchozí 0.75). Určuje, kdy dojde ke změně velikosti.
Proč jsou důležité hashCode() a equals():
- Správná funkce HashMap závisí na správné implementaci těchto metod.
- Pokud
equals()vracítruepro dva objekty,hashCode()by měl vracet stejnou hodnotu. - Nesprávná implementace může vést k tomu, že prvky nebudou nalezeny (
getvrátínull), i když byly přidány.
Příklad struktury Node:
// Pouze interně
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 zajišťuje rychlé (průměrně O(1)) přidávání, získávání a mazání prvků při rovnoměrném rozložení hashů. V nejhorším případě (silné kolize) může být operace O(n) nebo O(log n) s použitím stromů.