Java - int НЕ БУДЕТ переполняться хешированием

Итак, я только начинаю изучать объектно-ориентированное программирование на Java, и мне нужно сделать этот хешированный словарь. Я должен хешировать имя с помощью алгоритма и возвращать хэшированное значение. Лаборатория сказала сделать

int n = s.length();
for (int i = 0; i < n; i++)
hash = g * hash + s.charAt(i);

где g = 31, s = имя + фамилия;

и я посмотрел на это и поместил его в код. То, что я написал, было

public int hashCode()     // part of the Name class
{
    int h = 0;
    String bothNames = first + last;
    for (int i = 0; i < bothNames.length(); i++) {
        h += bothNames.charAt(i)*Math.pow(g, bothNames.length() - i-1);
    }
    return h;
}

Теперь, когда я запустил этот код для чего-то вроде Name testName = new Name("Wayne", "Gretzky"); и распечатал testName.hashCode(), я почти всегда возвращал ограничение на 32-битное целое, что означало, что он не переполнялся. Однако, когда я изменил цикл for на

for (int i = 0; i < bothNames.length(); i++) {
    h = g*h + bothNames.charAt(i);
}

вдруг снова переполнился. Я не очень понимаю, почему это могло произойти. Две хеш-функции должны быть одинаковыми. Почему h не переполняется в первом случае? Заранее спасибо.

«Две хэш-функции должны быть одинаковыми». Как вы это понимаете?

Robby Cornelissen 16.05.2022 03:30

Ну, исходная хеш-функция была h = u_0 g^(n - 1) + u_1 g^(n - 2) + … + u_(n - 2) g + u_(n - 1), и обе они должны выполнять то же самое, вы получаете термины один за другим, который был моим первоначальным, а новый делает это немного по-другому. Я работал с ними обоими, и похоже, что они должны быть одинаковыми, u_k * g^(n-k) — это терм в обеих хеш-функциях.

jettae schroff 16.05.2022 04:27
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
2
43
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Проблема в следующем:

h += bothNames.charAt(i)*Math.pow(g, bothNames.length() - i-1)

Метод pow возвращает большое значение double. Который вы умножаете на целое число, чтобы получить большее значение double. Затем h += ... выполняет преобразование примитивное сужение из double в int.

Преобразование double в int — это определенный для преобразования любого значения с плавающей запятой, превышающего Integer.MAX_VALUE, в Integer.MAX_VALUE (!).

Решением будет вычисление gk с помощью целочисленной арифметики; например используя повторение:

g0 = 1

gk = g * gk - 1 (for k > 0).

Давайте посмотрим на следующую строку:

h += bothNames.charAt(i) * Math.pow(g, bothNames.length() - i - 1);

Учитывая природу составные операторы присваивания, это эквивалентно:

h = (int)(h + (bothNames.charAt(i) * Math.pow(g, bothNames.length() - i - 1)));

Все бы ничего, если бы не тот факт, что Math.pow возвращает double. Принимая во внимание регулярные правила расширения:

h = (int)(intValue + (intValue * doubleValue))
h = (int)(intValue + doubleValue)
h = (int)(doubleValue)

Последнее doubleValue сужается до int. Если строка достаточно длинная, doubleValue превысит Integer.MAX_VALUE с первой итерации.

Другие вопросы по теме