Java: «простое» число или «сила двух» в качестве размера HashMap?
Многие книги и учебники говорят, что размер хеш-таблицы должен быть простым, чтобы равномерно распределять ключи во всех ведрах. Но Java HashMap
всегда использует размер, который имеет силу в два раза. Не следует ли использовать премьер? Что лучше, «премьер» или «сила двух» в качестве размера hash-таблицы?
- ConcurrentModificationException и HashMap
- Почему объект Object.toString () по умолчанию возвращает шестнадцатеричное представление hash-кода?
- Безопасно ли получать значения из java.util.HashMap из нескольких streamов (без изменений)?
- Как получить уникальный идентификатор объекта, который переопределяет hashCode ()?
- Доступ к последней записи на карте
- Хорошая hash-функция для строк
- Как я могу генерировать хеш MD5?
- Как отсортировать HashMap в Java
Использование мощности двух эффективно маскирует верхние биты хеш-кода. Таким образом, hash-функция некачественного качества может проявиться особенно плохо в этом сценарии.
HashMap
Java смягчает это, не hashCode()
реализации hashCode()
объекта и применяя второй уровень hashирования к его результату :
Применяет дополнительную хеш-функцию к заданному hash-коду, который защищает от hash-функций низкого качества. Это важно, потому что HashMap использует hash-таблицы с длиной в две строки, которые в противном случае сталкиваются с конфликтами для hash-кодов, которые не отличаются в младших битах.
Если у вас хорошая hash-функция или что-то похожее на то, что делает HashMap
, не имеет значения, используете ли вы простые числа и т. Д., Как размер таблицы.
Если, с другой стороны, хеш-функция имеет неизвестное или низкое качество, то использование простого номера будет более безопасной ставкой. Тем не менее, он будет делать таблицы с динамическим размером, чтобы реализовать, так как внезапно вам нужно будет создавать простые числа вместо того, чтобы просто умножать размер на постоянный коэффициент.
Стандартная реализация HashMap имеет hash
метод, который перехватывает hash-код вашего объекта, чтобы избежать этой ошибки. Комментарий перед методом hash()
:
/** * Retrieve object hash code and applies a supplemental hash function to the * result hash, which defends against poor quality hash functions. This is * critical because HashMap uses power-of-two length hash tables, that * otherwise encounter collisions for hashCodes that do not differ * in lower bits. Note: Null keys always map to hash 0, thus index 0. */
Единственный способ узнать, что лучше между простым и сильным, – это сравнить его.
Много лет назад, когда я писал ассемблер, чья производительность сильно зависела от поиска символа talbe, я тестировал это, используя большой блок сгенерированных идентификаторов. Даже с наивным отображением я обнаружил, что мощность двух, как и ожидалось, имела менее равномерное распределение и более длинные цепочки, чем простое количество кодов с одинаковым размером. Он по-прежнему работает быстрее, из-за скорости выбора ковша с помощью маскировки бит.
Я сильно подозреваю, что разработчики java.util не прибегли бы к дополнительному hashированию и силе двух, не сравнивая его с использованием простого количества ведер. Это очень очевидная вещь, когда нужно создавать хешированную структуру данных.
По этой причине я уверен, что размер перефразировки и мощности-два дает лучшую производительность для типичных hash-карт Java, чем простое количество ковшей.
С точки зрения производительности / расчета времени измерения мощности двух размеров могут быть рассчитаны с помощью только маскирования бит, которая быстрее, чем целочисленное деление, которое в противном случае потребовалось бы.
Вероятно, вы должны использовать таблицы хеш-размера, если вы используете квадратичное зондирование для разрешения конфликтов. Если у вас есть таблица с обычным размером, квадратичное зондирование ударит половину записей, меньше, если оно не является простым. Таким образом, вы можете найти подходящее место для хранения записи, даже если ваша хеш-таблица меньше половины. Поскольку hash-карты Java не используют квадратичное зондирование, нет необходимости использовать простые числа в качестве размера.