Ограничение размера карты с помощью Maps.newHashMapWithExpectedSize (…) в Java вызвало коллизии

1

Я пытался ограничить размер новой карты, которую я создавал с помощью метода Google Maps.newHashMapWithExpectedSize(n) в качестве (незначительной) пространственной оптимизации, так как я знал, сколько записей ключевого значения он будет содержать. Вместо того, чтобы вставлять каждую из новых пар ключ-значение в свой собственный ковш, произошло столкновение, и моя первая пара ключ-значение была перезаписана, несмотря на то, что два ключа были разными значениями. Мои ключи были объектами String и n = 3. Два ключа, которые хэшировали в том же ведре, были "records" и "pageSize".

Когда я изменил код, чтобы просто использовать Maps.newHashMap(), поведение было как и ожидалось, хотя оно создало неиспользуемое пространство в структуре данных. Мое предположение, без погружения в фактический код, заключается в том, что ограничение размера HashMap просто приводит к большей вероятности столкновений, хотя я бы подумал, что основная структура данных будет обрабатывать это немного более изящно. Поэтому мои вопросы:

  • Следует избегать newHashMapWithExpectedSize (n) при использовании небольших значений для n?
  • После вставки "записей" в карту, если бы я вызвал map.hasKey("pageSize"), я бы понял?
  • 0
    Конечно, это вызывает столкновения. Чего еще можно ожидать?
  • 0
    @EJP Тогда какой смысл newHashMapWithExpectedSize (), если при вставке новых значений они будут перезаписывать старые? И что было бы лучшим решением для ограничения пространственных ресурсов карты при одновременном обеспечении записи всех значений?
Показать ещё 1 комментарий
Теги:
collision
hashmap
guava

2 ответа

0

Вы уверены, что здесь указали всю информацию? Здесь интерактивный сеанс Scala, который показывает, что вы пытаетесь сделать:

scala> val map = com.google.common.collect.Maps.newHashMapWithExpectedSize[String, String](3)
map: java.util.HashMap[String,String] = {}

scala> map.put("pageSize", "foo")
res1: String = null

scala> map.put("records", "bar")
res2: String = null

scala> map.put("third", "3")
res3: String = null

scala> map.put("fourth", "4")
res4: String = null

scala> map.toString()
res5: String = {pageSize=foo, fourth=4, records=bar, third=3}

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

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

0

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

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

Следует избегать newHashMapWithExpectedSize (n) при использовании небольших значений для n?

Нет, не совсем. Действительно ли факт, что у вас столкновение является проблемой?

После вставки "записей" в карту, если бы я вызвал map.hasKey("pageSize"), я бы понял?

Если и только если вы добавили запись с ключом "pageSize". Хеширование в одно и то же ведро не влияет на поведение карты. Несколько записей могут храниться в каждом ведре, и только если найден ключ, равный параметру "pageSize", hasKey возвращает true.

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

Можете ли вы использовать ImmutableMap вместо этого? Часто, когда вы заранее знаете, сколько записей будет содержать карта, она должна быть неизменной. Поскольку ImmutableMap знает, что количество содержащихся в нем записей никогда не изменится, возможно, он будет оптимизировать свой размер лучше, чем измененный HashMap. Не говоря уже о других преимуществах неизменности.

  • 0
    Столкновение на самом деле является проблемой, так как я хотел пары ключ-значение для «records» и «pageSize», но после вставки «pageSize» ключ и значение «records» были перезаписаны. Я могу использовать ImmutableMap, и с тех пор я исправил ситуацию, используя HashMap без ожидаемого размера. Мне было просто любопытно, почему два ключа хэшируют один и тот же сегмент, когда карта была построена с ожидаемым размером, и не хэшируют один и тот же сегмент, если это не так. Я вполне уверен, что вероятность того, что две строки хэшируют одно и то же значение, мала.
  • 2
    @mattforni: HashMap не перезаписывает один ключ другим ключом, независимо от того, как он создан. Период. Должно быть что-то еще, и вам нужно предоставить SSCCE, который продемонстрирует вашу проблему, если мы хотим помочь вам разобраться с этим.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню