Хеш-таблицы
Зачем нужны хеш-таблицы
Во многих алгоритмических задачах постоянно повторяется один и тот же вопрос: «мы уже встречали это значение?» или «какие данные связаны с этим ключом?». Если каждый раз просматривать массив с начала, один поиск может занимать O(n). Хеш-таблица позволяет организовать данные так, чтобы поиск, добавление и удаление в среднем выполнялись за O(1).
За этой скоростью стоит простая идея: ключ преобразуется в хеш, а хеш помогает быстро выбрать место, где нужно искать запись. Но между этой идеей и надёжной структурой данных есть несколько важных шагов — хорошая хеш-функция, обработка коллизий и правильный выбор между хранением пар «ключ — значение» и простым множеством значений.
Что входит в раздел
- Основы хеш-таблиц. Разберём общую схему «ключ → хеш → корзина» и поймём, откуда берётся быстрый доступ к данным.
- Хеш-функции. Поговорим о свойствах хеша и о том, почему одинаковые ключи должны обрабатываться согласованно.
- Коллизии. Увидим, почему разные ключи иногда попадают в одно место и как хеш-таблица сохраняет корректность в такой ситуации.
- Hash Map. Научимся быстро находить значение по ключу и выбирать такую структуру для алгоритмических задач.
- Hash Set. Разберём хранение уникальных значений и быстрые проверки принадлежности множеству.
- Частотная карта. Освоим один из самых частых приёмов: подсчёт количества появлений каждого значения.
- Паттерны быстрого поиска. Соединим знания раздела и увидим, как дополнительная память помогает заменять повторные линейные поиски быстрыми проверками.
Одна структура — много алгоритмических приёмов
Set<Integer> seen = new HashSet<>();
seen.add(42);
boolean exists = seen.contains(42);
Здесь проверка наличия значения выглядит почти как обычный вопрос к структуре данных. В следующих темах разберём, почему такая проверка может быть быстрой и как на той же идее строятся карты, множества, подсчёты частот и многие задачи на поиск.