Почему Java hashCode () в String использует 31 в качестве множителя?

TASKLIST | FINDSTR ProgramName || START "" "Path\ProgramName.exe"
449
задан Mark Amery 3 January 2019 в 13:14
поделиться

6 ответов

По словам Joshua Bloch Эффективный Java (книга, которой нельзя рекомендовать достаточно, и которую я купил благодаря непрерывным упоминаниям на stackoverflow):

значение 31 было выбрано, потому что это - нечетное начало. Если бы это было даже и переполненное умножение, информация была бы потеряна, поскольку умножение 2 эквивалентно смещению. Преимущество использования начала менее ясно, но это традиционно. Хорошее свойство 31 - то, что умножение может быть заменено сдвигом и вычитанием для лучшей производительности: 31 * i == (i << 5) - i. Современные VMs делают этот вид оптимизации автоматически.

(из Главы 3, Объект 9: Всегда переопределяйте хэш-код, когда Вы переопределяете, равняется, страница 48)

376
ответ дан matt b 3 January 2019 в 13:14
поделиться

На (главным образом) старых процессорах, умножающихся на 31, может быть относительно дешевым. На ARM, например, это - только одна инструкция:

RSB       r1, r0, r0, ASL #5    ; r1 := - r0 + (r0<<5)

Большинство других процессоров потребовало бы отдельного сдвига и вычло бы инструкцию. Однако, если Ваш множитель является медленным, это - все еще победа. Современные процессоры имеют тенденцию иметь быстрые множители, таким образом, это не имеет большого значения, пока 32 идет на корректную сторону.

Это не большой хеш-алгоритм, но это достаточно хорошо и лучше, чем 1,0 кода (и намного лучше, чем 1,0 спецификации!).

55
ответ дан mikej 3 January 2019 в 13:14
поделиться

Как указывают Гудрич и Tamassia, Если Вы примете 50 000 английских слов (сформированный как объединение списков слов, предоставленных в двух вариантах Unix), с помощью констант 31, 33, 37, то 39, и 41 произведет меньше чем 7 коллизий в каждом случае. Зная это, это не должно удивлять, что много реализаций Java выбирают одну из этих констант.

По совпадению, я был посреди чтения раздела "полиномиальными хэш-кодами", когда я видел этот вопрос.

РЕДАКТИРОВАНИЕ: вот ссылка на ~10mb книгу PDF, которую я отсылаю к вышеупомянутому. Посмотрите раздел 10.2 Хэш-таблиц (страница 413) Структуры данных и Алгоритмы в Java

77
ответ дан JohnZaj 3 January 2019 в 13:14
поделиться

Я не уверен, но я предположил бы, что они протестировали некоторый образец простых чисел и нашли, что 31 дал лучшее распределение по некоторому образцу возможных Строк.

4
ответ дан Dave L. 3 January 2019 в 13:14
поделиться

При умножении биты сдвигаются влево. Это использует больше доступного пространства хэш-кодов, уменьшая коллизии.

Если не использовать степень двойки, младшие, крайние правые биты также заполняются для смешивания со следующей частью данных, входящей в хэш .

Выражение n * 31 эквивалентно (n << 5) - n .

30
ответ дан 22 November 2019 в 22:57
поделиться

Блох не совсем вникает в это, но я всегда слышал / верил в обоснование того, что это базовая алгебра. Хеши сводятся к операциям умножения и модуля, что означает, что вы никогда не захотите использовать числа с общими множителями, если можете. Другими словами, относительно простые числа обеспечивают равномерное распределение ответов.

Обычно используются следующие числа:

  • модуль типа данных, который вы помещаете в (2 ^ 32 или 2 ^ 64)
  • модуль количества сегментов в вашем hashtable (варьируется. В java раньше было простое число, теперь 2 ^ n)
  • умножьте или сдвиньте на магическое число в вашей функции смешивания
  • Входное значение

Вы действительно можете управлять только парой из этих значений , так что требуется дополнительная осторожность.

4
ответ дан 22 November 2019 в 22:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: