Menu
Coddy logo textTech

Hash Map

Последнее обновление

Hash map хранит пары ключ-значение и позволяет искать значение по его ключу в среднем за O(1). Она работает точно так же, как хеш-таблица, но каждая запись корзины несёт и ключ, и связанное с ним значение. Чтобы сохранить или получить пару, ключ хешируется в индекс корзины, затем цепочка этой корзины просматривается в поисках совпадающего ключа. Нажмите воспроизведение выше, чтобы увидеть, как пары размещаются по хешированной корзине и значение извлекается по своему ключу.

Это структура, лежащая в основе dict в Python, HashMap в Java и Map/объектов в JavaScript. Коллизии обрабатываются так же, как в хеш-таблице - здесь методом раздельных цепочек - поэтому производительность зависит от хорошей хеш-функции и низкого коэффициента заполнения.

Временная сложность

ОперацияСредний случайХудший случай
Вставка/обновление (put)O(1)O(n)
Поиск (get)O(1)O(n)
УдалениеO(1)O(n)
ПамятьO(n)O(n)

Hash map в популярных языках

ЯзыкТип
Pythondict
JavaHashMap
JavaScriptMap / объект
C++std::unordered_map
Gomap

Разобранный пример

Вставка пар ("cat", 3), ("dog", 5), ("cat", 9), ("emu", 7) в карту с 8 корзинами, используя hash(key) % 8. Предположим, hash("cat") % 8 = 2, hash("dog") % 8 = 5, hash("emu") % 8 = 2:

ШагСтруктураДействие
Put ("cat", 3)корзина 2: [("cat", 3)]Хешируется в корзину 2; цепочка пуста, поэтому пара добавляется.
Put ("dog", 5)корзина 2: [("cat", 3)], корзина 5: [("dog", 5)]Хешируется в корзину 5; цепочка пуста, поэтому пара добавляется.
Put ("cat", 9)корзина 2: [("cat", 9)], корзина 5: [("dog", 5)]Хешируется в корзину 2; ключ "cat" уже в цепочке, поэтому его значение обновляется до 9.
Put ("emu", 7)корзина 2: [("cat", 9), ("emu", 7)], корзина 5: [("dog", 5)]Хешируется в корзину 2; коллизия с "cat", ключ не найден, поэтому пара добавляется.
Get "emu"корзина 2: [("cat", 9), ("emu", 7)]Хешируется в корзину 2; цепочка просматривается, "cat" пропускается, "emu" совпадает, возвращается 7.

Когда использовать hash map

Используйте, когдаИзбегайте, когда
Нужны поиск, вставка и удаление за средние O(1) по точному ключу.Нужно хранить ключи в отсортированном порядке или делать запросы по диапазону - используйте сбалансированное BST или отсортированную карту.
Ключи хешируемы и равенство чётко определено (строки, целые, кортежи).Ключи изменяемы и могут меняться после вставки, что портит их корзину.
Вы считаете, устраняете дубли, кешируете или индексируете по идентификатору.Нужны гарантии худшего случая O(log n), а не амортизированные средние границы.
Порядок обхода не важен или достаточно карты с порядком вставки.Память очень ограничена - корзины, запас коэффициента заполнения и указатели добавляют накладные расходы.

Код Hash Map

Чистая, готовая к запуску реализация Hash Map на Python, JavaScript, Java, C++, C. Выберите язык, скопируйте код или откройте его уже загруженным в плейграунде Coddy.

Код Hash Map на 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))
Запустите этот код в плейграунде Python

Частые вопросы о hash map

В чём разница между hash map и хеш-таблицей?
По сути это одна и та же структура - массив корзин, адресуемых по хешу ключа. В общем употреблении "хеш-таблица" часто означает набор ключей или общую технику, тогда как "hash map" подчёркивает хранение пар ключ-значение. Некоторые языки также проводят различие по потокобезопасности (например, Hashtable и HashMap в Java), но основной алгоритм идентичен.
Какова временная сложность hash map?
Put, get и delete в среднем O(1) при хорошей хеш-функции и низком коэффициенте заполнения. В патологическом случае, когда все ключи сталкиваются в одной корзине, они вырождаются до O(n), поэтому важны увеличение размера и хорошее хеширование.
Как hash map обрабатывает два ключа, которые хешируются в одну корзину?
Она разрешает коллизию. Эта визуализация использует метод раздельных цепочек: каждая корзина хранит небольшой список, и новая пара, чей ключ туда хешируется, добавляется в этот список. При поиске карта просматривает короткую цепочку в поисках совпадающего ключа. Альтернативная техника - открытая адресация, которая пробует другую ячейку массива.
Hash map или двоичное дерево поиска: что выбрать?
Используйте hash map, когда нужен только поиск по точному ключу и вы хотите операции за средние O(1). Используйте сбалансированное двоичное дерево поиска (например, TreeMap или std::map), когда нужны отсортированные ключи, запросы по диапазону или поиск предшественника/преемника, что стоит O(log n). BST меняет немного скорости на гарантии упорядоченности, которые hash map предоставить не может.
Что такое коэффициент заполнения и почему он запускает увеличение размера?
Коэффициент заполнения - это отношение числа хранимых записей к числу корзин. По мере его роста цепочки удлиняются, а средние поиски замедляются, поэтому большинство реализаций увеличивают размер (обычно удваивают корзины и перехешируют всё), когда он превышает порог вроде 0.75. Увеличение размера - это O(n), но редкое, поэтому оно амортизируется и удерживает средние операции на уровне O(1).
Можно ли использовать изменяемый объект вроде списка в качестве ключа hash map?
Обычно нет. Ключи должны быть хешируемыми, и их хеш должен оставаться постоянным, пока они в карте - Python, например, выбрасывает TypeError: unhashable type для list. Если изменить ключ после вставки, его хеш меняется, и карта больше не может найти его в правильной корзине, молча теряя запись. Используйте неизменяемые ключи, такие как строки, числа или кортежи.
Coddy programming languages illustration

Освойте алгоритмы с Coddy

НАЧАТЬ