Что означает, что хэш-таблица открыта в Java?

Я читал документы Java API по классу Hashtable и столкнулся с несколькими вопросами. В документе говорится: «Обратите внимание, что хэш-таблица открыта: в случае "коллизии хэшей" в одной корзине хранится несколько записей, которые необходимо искать последовательно. " Я пробовал следующее код сам

Hashtable<String, Integer> me = new Hashtable<String, Integer>();
me.put("one", new Integer(1));
me.put("two", new Integer(2));
me.put("two", new Integer(3));
System.out.println(me.get("one"));  
System.out.println(me.get("two"));

результат был

1
3
  1. Это то, что имеется в виду под словом «открыто»?
  2. что случилось с целым числом 2? собирают как мусор?
  3. Есть ли "закрытый" пример?

person derrdji    schedule 17.08.2009    source источник


Ответы (6)


Нет, это не то, что подразумевается под «открытым».

Обратите внимание на разницу между коллизией key и коллизией хэша.

Hashtable не допустит более одной записи с одним и тем же ключом (как в вашем примере, вы поместили две записи с ключом «два», вторая (3) заменила первую (2) , и у вас остался только второй в Hashtable).

Конфликт хэш возникает, когда два разных ключа имеют одинаковый хэш-код (возвращаемый их методом hashCode()). Различные реализации хеш-таблиц могут относиться к этому по-разному, в основном с точки зрения низкоуровневой реализации. Будучи «открытым», Hashtable будет хранить связанный список записей, чьи ключи имеют одинаковое значение. В худшем случае это может привести к производительности O(N) для простых операций, которая обычно была бы O(1) в хеш-карте, где хэши в основном были разными значениями.

person Avi    schedule 17.08.2009
comment
Как я могу избежать хеширования разных значений для одного ключа? - person derrdji; 17.08.2009
comment
Чтобы помочь в понимании: посмотрите на источник String.hashCode() и распечатайте вывод one.hashCode() и two.hashCode(). - person basszero; 17.08.2009
comment
@derrdji: В общем, hashCode() должен быть реализован таким образом, чтобы сделать маловероятным хеширование разных значений для одного и того же ключа. Если вы реализуете свои собственные классы в качестве ключей, и особенно если вы переопределяете метод equals(), вы также должны предоставить хороший метод hashCode(). Для получения дополнительной информации о теории хеш-функций см.: en.wikipedia.org/wiki/Hash_function - person Avi; 17.08.2009
comment
Обратите внимание, что хеширование двух разных значений с одним и тем же хэш-кодом или с разными хэш-кодами не оказывает ФУНКЦИОНАЛЬНОГО влияния на вашу программу. Одна из вещей, которую HashTable и HashMap делают для вас, — это рассмотрение этого дела за кулисами. Единственная разница, которую он имеет, - это разница в производительности. Если бы в худшем случае каждый ключ, который вы добавили в хеш-таблицу, имел один и тот же хеш-код, вы бы закончили тем, что при каждом обращении выполняли бы последовательный поиск по всему списку, а не переходили бы в нужное место, и производительность упала бы. Но программа все равно будет работать. - person Jay; 17.08.2009
comment
Сам Object.hashCode() является своего рода ключом для Hashtable. В документах говорится о столкновении значений hashed hashCode(), что является более общим, чем просто столкновение hashCode(). - person Aleksey Otrubennikov; 09.03.2012

Это означает, что два элемента с разными ключами и одинаковым хэш-кодом попадают в одно и то же ведро.

В вашем случае ключи "два" одинаковы, поэтому второй ввод перезаписывает первый.

Но если предположить, что у вас есть собственный класс

class Thingy {
    private final String name;

    public Thingy(String name) {
         this.name = name;
    }

    public boolean equals(Object o) {
        ...

    }

    public int hashcode() {
       //not the worlds best idea
       return 1;
    }

}

И создал несколько его экземпляров. то есть

Thingy a = new Thingy("a"); 
Thingy b = new Thingy("b"); 
Thingy c = new Thingy("c"); 

И вставил их в карту. Тогда одно ведро, то есть ведро, содержащее материал с хэш-кодом 1, будет содержать список (цепочку) из трех элементов.

Map<Thingy, Thingy> map = new HashMap<Thingy, Thingy>();
map.put(a, a);
map.put(b, b);
map.put(c, c);

Таким образом, получение элемента с помощью любого ключа Thingy приведет к поиску хэш-кода O (1), за которым следует линейный поиск O (n) в списке элементов в корзине с хэш-кодом 1.

Также будьте осторожны, чтобы убедиться, что вы соблюдаете правильные отношения при реализации hashcode и equals. А именно, если два объекта равны, то они должны иметь одинаковый хэш-код, но не обязательно наоборот, поскольку несколько ключей могут получить один и тот же хэш-код.

Да, и полные определения открытого хеширования и закрытых хэш-таблиц смотрите здесь http://www.c2.com/cgi/wiki?HashTable

person pjp    schedule 17.08.2009
comment
Отличный ответ, даже без иронически заниженной не лучшей в мире идеи. +1, но я бы проголосовал дважды, если бы мне позволили. :) - person CPerkins; 17.08.2009

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

Сегмент 0: Ничего
Сегмент 1: Элемент 1
Сегмент 2: Элемент 2 -> Элемент 3
Сегмент 3: Ничего
Сегмент 4: Элемент 4

В этом случае, если вы ищете ключ, хэш которого соответствует корзине 2, вы должны затем выполнить поиск O(n) в списке, чтобы найти ключ, который соответствует тому, что вы ищете. Если ключ хэширует на Bucket 0, 1, 3 или 4, вы получаете производительность поиска O(1).

person Ryan Ahearn    schedule 17.08.2009

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

person Bill the Lizard    schedule 17.08.2009
comment
Я проверил исходный код, и Hashtable, и Hashmap используют цепочку. На самом деле это противоположность открытой адресации, и каждый хэш-код может занимать только один адрес в массиве. Примером открытой адресации может быть линейное зондирование. FWIW, терминология сбивает с толку: открытое хеширование — это полная противоположность открытой адресации. - person Sean Reilly; 17.08.2009
comment
@Sean: Это сбивает с толку! Я исправил свою ошибку. Спасибо, что оставили комментарий. - person Bill the Lizard; 17.08.2009

Хэш — это вычисляемая функция, которая отображает один объект («один» или «два» в вашем образце) в (в данном случае) целое число. Это означает, что может быть несколько значений, которые сопоставляются с одним и тем же целым числом (целое число имеет конечное число разрешенных значений, в то время как может быть бесконечное количество входных данных). В этом случае «равные» должны уметь различать этих двоих. Таким образом, ваш пример кода правильный, но может быть какой-то другой ключ с таким же хэш-кодом (и он будет помещен в то же ведро, что и «два»)

person krosenvold    schedule 17.08.2009

Предупреждение: существуют противоречивые определения "открытого хеширования" в общем употреблении:

Цитата из http://www.c2.com/cgi/wiki?HashTable в другом ответе:

Внимание: некоторые люди используют термин «открытое хеширование» для обозначения того, что я здесь назвал «закрытым хэшированием»! Использование здесь соответствует использованию в TheArtOfComputerProgramming и IntroductionToAlgorithms, оба из которых являются рекомендуемыми ссылками, если вы хотите узнать больше о хеш-таблицах.

Например, приведенная выше страница определяет «открытое хеширование» следующим образом:

Есть две основные стратегии. Открытое хеширование, также называемое открытой адресацией, гласит: когда запись в таблице, необходимая для новой пары ключ/значение, уже занята, найдите каким-то образом другую неиспользуемую запись и поместите ее туда. Закрытое хеширование говорит: каждая запись в таблице представляет собой вторичную структуру данных (обычно связанный список, но есть и другие возможности), содержащую фактические данные, и эта структура данных может быть расширена без ограничений.

Напротив, Википедия дает следующее определение:

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

Если так называемые «эксперты» не могут договориться о том, что означает термин «открытое хеширование», лучше его не использовать.

person Stephen C    schedule 17.08.2009