Menu
Coddy logo textTech

Mapa haszująca (HashMap)

Ostatnia aktualizacja

Mapa haszująca przechowuje pary klucz-wartość i pozwala znaleźć wartość po kluczu średnio w O(1). Działa dokładnie jak tablica haszująca, ale każdy wpis w kubełku zawiera zarówno klucz, jak i przypisaną mu wartość. Aby zapisać lub pobrać parę, klucz jest haszowany do indeksu kubełka, a potem łańcuch w kubełku jest przeglądany w poszukiwaniu pasującego klucza. Kliknij odtwarzanie powyżej i zobacz, jak pary trafiają do kubełków według hasza, a wartość jest pobierana po kluczu.

To struktura stojąca za dict w Pythonie, HashMap w Javie oraz Map/obiektami w JavaScripcie. Kolizje są obsługiwane tak samo jak w tablicy haszującej, tutaj metodą łańcuchową, więc wydajność zależy od dobrej funkcji haszującej i niskiego współczynnika zapełnienia.

Złożoność czasowa

OperacjaŚrednioNajgorszy przypadek
Put (wstawienie/aktualizacja)O(1)O(n)
Get (wyszukiwanie)O(1)O(n)
UsuwanieO(1)O(n)
PamięćO(n)O(n)

Mapa haszująca w popularnych językach

JęzykTyp
Pythondict
JavaHashMap
JavaScriptMap / obiekt
C++std::unordered_map
Gomap

Przykład krok po kroku

Wstawianie par ("cat", 3), ("dog", 5), ("cat", 9), ("emu", 7) do mapy z 8 kubełkami przy użyciu hash(key) % 8. Załóżmy, że hash("cat") % 8 = 2, hash("dog") % 8 = 5, hash("emu") % 8 = 2:

KrokStrukturaDziałanie
Put ("cat", 3)kubełek 2: [("cat", 3)]Hasz wskazuje kubełek 2; łańcuch jest pusty, więc dopisz parę.
Put ("dog", 5)kubełek 2: [("cat", 3)], kubełek 5: [("dog", 5)]Hasz wskazuje kubełek 5; łańcuch jest pusty, więc dopisz parę.
Put ("cat", 9)kubełek 2: [("cat", 9)], kubełek 5: [("dog", 5)]Hasz wskazuje kubełek 2; klucz "cat" jest już w łańcuchu, więc zaktualizuj jego wartość na 9.
Put ("emu", 7)kubełek 2: [("cat", 9), ("emu", 7)], kubełek 5: [("dog", 5)]Hasz wskazuje kubełek 2; kolizja z "cat", klucza nie ma, więc dopisz parę.
Get "emu"kubełek 2: [("cat", 9), ("emu", 7)]Hasz wskazuje kubełek 2; przejrzyj łańcuch, pomiń "cat", dopasuj "emu", zwróć 7.

Kiedy używać mapy haszującej

Używaj, gdyUnikaj, gdy
Potrzebujesz średnio O(1) na wyszukiwanie, wstawianie i usuwanie po dokładnym kluczu.Potrzebujesz kluczy w posortowanej kolejności lub zapytań o zakres: użyj zrównoważonego drzewa BST lub mapy posortowanej.
Klucze da się haszować, a równość jest dobrze zdefiniowana (napisy, liczby całkowite, krotki).Klucze są modyfikowalne i mogą się zmienić po wstawieniu, co psuje ich kubełek.
Zliczasz, usuwasz duplikaty, cache'ujesz lub indeksujesz po identyfikatorze.Potrzebujesz gwarancji O(log n) w najgorszym przypadku zamiast zamortyzowanych średnich ograniczeń.
Kolejność iteracji nie ma znaczenia albo wystarczy mapa zachowująca kolejność wstawiania.Pamięci jest bardzo mało: kubełki, zapas na współczynnik zapełnienia i wskaźniki dodają narzut.

Hash Map: kod

Przejrzysta, gotowa do uruchomienia implementacja algorytmu Hash Map w językach: Python, JavaScript, Java, C++, C. Wybierz język, skopiuj kod albo otwórz go od razu w edytorze online Coddy.

Hash Map: kod (Python)

Python
1# Python's built-in dict is a hash map: O(1) average2# insert, lookup, and delete.3inventory = {"apple": 3, "banana": 7}4
5# Insert and update6inventory["cherry"] = 57inventory["apple"] += 28
9# Lookup, with .get for a safe default on missing keys10print("apple: ", inventory["apple"])11print("mango: ", inventory.get("mango", 0))12
13# Membership test and delete14print("banana in stock:", "banana" in inventory)15del inventory["banana"]16print("banana in stock:", "banana" in inventory)17
18# Iterate over key-value pairs19for fruit, count in sorted(inventory.items()):20    print(f"{fruit}: {count}")21
22# Classic hash map use case: counting frequencies23words = "the quick brown fox jumps over the lazy dog the end".split()24freq = {}25for word in words:26    freq[word] = freq.get(word, 0) + 127
28print("Occurrences of the:", freq["the"])29print("Most common word:  ", max(freq, key=freq.get))
Uruchom ten kod w edytorze Python online

Mapa haszująca: najczęstsze pytania

Czym różni się mapa haszująca od tablicy haszującej?
To w zasadzie ta sama struktura: tablica kubełków adresowanych haszem klucza. W potocznym użyciu "tablica haszująca" często oznacza zbiór kluczy lub ogólną technikę, a "mapa haszująca" podkreśla przechowywanie par klucz-wartość. Niektóre języki rozróżniają je też pod względem bezpieczeństwa wątków (np. Hashtable i HashMap w Javie), ale główny algorytm jest identyczny.
Jaka jest złożoność czasowa mapy haszującej?
Put, get i usuwanie mają średnio złożoność O(1) przy dobrej funkcji haszującej i niskim współczynniku zapełnienia. W patologicznym przypadku, gdy wszystkie klucze kolidują w jednym kubełku, degradują się do O(n), dlatego zmiana rozmiaru i dobre haszowanie mają znaczenie.
Jak mapa haszująca obsługuje dwa klucze trafiające do tego samego kubełka?
Rozwiązuje kolizję. Ta wizualizacja używa metody łańcuchowej: każdy kubełek przechowuje małą listę, a nowa para, której klucz trafia do tego kubełka, jest dopisywana do listy. Przy wyszukiwaniu mapa przegląda krótki łańcuch w poszukiwaniu pasującego klucza. Alternatywną techniką jest adresowanie otwarte, które szuka innego wolnego miejsca w tablicy.
Mapa haszująca czy binarne drzewo poszukiwań: co wybrać?
Użyj mapy haszującej, gdy potrzebujesz tylko wyszukiwania po dokładnym kluczu i chcesz operacji średnio w O(1). Użyj zrównoważonego binarnego drzewa poszukiwań (jak TreeMap lub std::map), gdy potrzebujesz kluczy w posortowanej kolejności, zapytań o zakres lub szukania poprzednika i następnika, które kosztują O(log n). Drzewo BST oddaje trochę szybkości w zamian za gwarancje porządku, których mapa haszująca nie zapewnia.
Czym jest współczynnik zapełnienia i dlaczego wywołuje zmianę rozmiaru?
Współczynnik zapełnienia to stosunek liczby zapisanych wpisów do liczby kubełków. Gdy rośnie, łańcuchy się wydłużają, a średnie wyszukiwanie zwalnia, więc większość implementacji zmienia rozmiar (zwykle podwaja liczbę kubełków i haszuje wszystko od nowa), gdy przekroczy on próg, na przykład 0.75. Zmiana rozmiaru kosztuje O(n), ale zdarza się rzadko, więc jej koszt się amortyzuje, a średnie operacje pozostają w O(1).
Czy mogę użyć modyfikowalnego obiektu, na przykład listy, jako klucza mapy haszującej?
Zwykle nie. Klucze muszą dać się haszować, a ich hasz musi pozostać stały, dopóki są w mapie; Python zgłasza na przykład TypeError: unhashable type dla list. Jeśli zmodyfikujesz klucz po wstawieniu, jego hasz się zmieni i mapa nie znajdzie go już we właściwym kubełku, po cichu gubiąc wpis. Używaj niemodyfikowalnych kluczy, takich jak napisy, liczby czy krotki.
Ilustracja języków programowania w Coddy

Opanuj algorytmy z Coddy

ZACZNIJ