Какую функцию хеширования использует Java для реализации класса Hashtable? - PullRequest
49 голосов
/ 20 февраля 2012

Из книги CLRS («Введение в алгоритмы») есть несколько хеш-функций, таких как mod, умножение и т. Д.

Какую хеш-функцию использует Java для сопоставления ключей со слотами?

Я видел здесь вопрос Функция хеширования, используемая в языке Java .Но это не отвечает на вопрос, и я думаю, что отмеченный ответ на этот вопрос неправильный.В нем говорится, что hashCode () позволяет вам выполнять собственную функцию хеширования для Hashtable, но я думаю, что это неправильно.

Целое число, возвращаемое hashCode (), является реальным ключом для Hashtble, тогда Hashtable использует функцию хеширования дляhash hashCode ().Этот ответ подразумевает, что Java дает вам возможность дать Hashtable функцию хеширования, но нет, это неправильно.hashCode () дает реальный ключ, а не функцию хеширования.

Так, что именно функция хеширования использует Java?

Ответы [ 6 ]

94 голосов
/ 20 февраля 2012

Когда ключ добавляется или запрашивается из HashMap в OpenJDK, последовательность выполнения выглядит следующим образом:

  1. Ключ преобразуется в 32-разрядное значение с использованием метода hashCode(), определенного разработчиком.
  2. 32-битное значение затем преобразуется второй хеш-функцией (ответ Эндрю содержит исходный код) в смещение внутри хеш-таблицы. Эта вторая хеш-функция обеспечивается реализацией HashMap и не может быть переопределена разработчиком.
  3. Соответствующая запись хеш-таблицы содержит ссылку на связанный список или ноль, если ключ еще не существует в хеш-таблице. Если есть коллизии (несколько ключей с одинаковым смещением), ключи вместе с их значениями просто собираются в односвязный список.

Если размер хеш-таблицы был выбран достаточно высоким, количество коллизий будет ограничено. Таким образом, один поиск занимает в среднем только постоянное время. Это называется ожидаемое постоянное время . Однако, если злоумышленник имеет контроль над ключами, вставленными в хеш-таблицу, и знает об используемом алгоритме хеширования, он может спровоцировать множество коллизий хеширования и, следовательно, форсировать время линейного поиска. Вот почему некоторые реализации хеш-таблиц были недавно изменены, чтобы включить случайный элемент, который затрудняет злоумышленнику прогнозировать, какие ключи вызовут коллизии.

Некоторые ASCII art

key.hashCode()
     |
     | 32-bit value
     |                              hash table
     V                            +------------+    +----------------------+
HashMap.hash() --+                | reference  | -> | key1 | value1 | null |
                 |                |------------|    +----------------------+
                 | modulo size    | null       |
                 | = offset       |------------|    +---------------------+
                 +--------------> | reference  | -> | key2 | value2 | ref |
                                  |------------|    +---------------------+
                                  |    ....    |                       |
                                                      +----------------+
                                                      V
                                                    +----------------------+
                                                    | key3 | value3 | null |
                                                    +----------------------+
27 голосов
/ 20 февраля 2012

Согласно источнику hashmap, каждый hashCode хэшируется с использованием следующего метода:

 /**
 * Applies a supplemental hash function to a given hashCode, 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.
 */
static int hash(int h) {
    // This function ensures that hashCodes that differ only by
    // constant multiples at each bit position have a bounded
    // number of collisions (approximately 8 at default load factor).
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}

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

HashMap также использует метод для определения индекса хеш-кода (поскольку длина всегда является степенью 2, вы можете использовать & вместо%):

/**
 * Returns index for hash code h.
 */
static int indexFor(int h, int length) {
    return h & (length-1);
}

Метод put выглядит примерно так:

int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);

Цель хеш-кода - предоставить уникальное целочисленное представление для данного объекта. Таким образом, имеет смысл, что метод hashCode Integer просто возвращает значение, поскольку каждое значение будет уникальным для этого объекта Integer.

4 голосов
/ 05 декабря 2013

Хеширование в целом делится на два этапа: а.HashCode б.Сжатие

На шаге а.генерируется целое число, соответствующее вашему ключу.Это может быть изменено вами в Java.

На шаге b.Java применяет метод сжатия, чтобы отобразить целое число, возвращаемое на шаге a.в слот в хэш-карте или хэш-таблице.Эту технику сжатия нельзя изменить.

0 голосов
/ 14 мая 2019
/**
 * Computes key.hashCode() and spreads (XORs) higher bits of hash
 * to lower.  Because the table uses power-of-two masking, sets of
 * hashes that vary only in bits above the current mask will
 * always collide. (Among known examples are sets of Float keys
 * holding consecutive whole numbers in small tables.)  So we
 * apply a transform that spreads the impact of higher bits
 * downward. There is a tradeoff between speed, utility, and
 * quality of bit-spreading. Because many common sets of hashes
 * are already reasonably distributed (so don't benefit from
 * spreading), and because we use trees to handle large sets of
 * collisions in bins, we just XOR some shifted bits in the
 * cheapest possible way to reduce systematic lossage, as well as
 * to incorporate impact of the highest bits that would otherwise
 * never be used in index calculations because of table bounds.
 */
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

Это последняя хеш-функция, используемая классом hashMap в java

0 голосов
/ 04 марта 2013

Проще говоря, второе хэширование - это не что иное, как поиск номера индекса массива сегментов, в котором будет храниться новая пара ключ-значение.Это отображение сделано для получения номера индекса из большего значения int хеш-кода ключа obj.Теперь, если два неравных ключевых объекта имеют одинаковый хеш-код, произойдет столкновение, поскольку они будут сопоставлены с одним и тем же индексом массива.В этом случае второй ключ вместе с его значением будет добавлен в связанный список.Здесь индекс массива будет указывать на последний добавленный узел.

0 голосов
/ 20 февраля 2012

Я думаю, здесь есть некоторая путаница с понятием.Хеш-функция преобразует входные данные переменного размера в выходные данные фиксированного размера (значение хеш-функции).В случае объектов Java выходные данные представляют собой 32-разрядное целое число со знаком.

Hashtable Java использует значение хеш-функции в качестве индекса в массиве, где хранится фактический объект, принимая во внимание арифметику по модулю и столкновения.Однако это не хэширование.

Реализация java.util.HashMap выполняет некоторое дополнительное переключение битов в значении хеша перед индексацией, чтобы в некоторых случаях защитить от чрезмерных коллизий.Это называется «дополнительный хэш», но я не думаю, что это правильный термин.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...