Как проверить хеш-функцию?

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

РЕДАКТИРОВАТЬ: Для пояснения, моя проблема заключалась в том, что я использовал значения long в Java таким образом, что первые 32 бита кодировали идентификатор, а вторые 32 бита кодировали другой идентификатор. К сожалению, хеш длинных значений Java просто выполняет XOR первых 32 бит со вторыми 32 битами, что в моем случае привело к очень низкой производительности при использовании в HashMap. Поэтому мне нужен другой хеш, и я хотел бы иметь модульный тест, чтобы эта проблема больше не влезала.

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

user3850 25.12.2008 03:30

На самом деле я не использую все 64-битное пространство, его достаточно, чтобы сгенерировать миллион или около того чисел, которые я обычно использую и тестирую с ними.

martinus 26.12.2008 14:35
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
24
2
15 310
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Если вы используете хеш-таблицу с цепочкой, вас действительно волнует количество коллизий. Это было бы тривиально реализовать в виде простого счетчика в вашей хеш-таблице. Каждый раз, когда элемент вставлен и таблица должна быть связана, увеличивайте счетчик цепочки. Более совершенный алгоритм хеширования приведет к меньшему количеству коллизий. Хорошая функция хеширования таблицы общего назначения, которую стоит проверить: djb2

Во-первых, я думаю, вы должны определить, что вы подразумеваете под хорошим распространением. Вы имеете в виду хороший спред для всех возможных входных данных или просто хороший спред для вероятных входных данных?

Например, если вы хешируете строки, которые представляют правильные полные (имя и фамилию) имена, вы, вероятно, не будете заботиться о том, как обстоят дела с хешем числовых символов ASCII.

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

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

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

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

Однако вы упомянули, что ваше приложение использует long для хранения двух независимых 32-битных значений. Попробуйте создать выборку значений, аналогичных тем, которые вы собираетесь использовать на самом деле, а затем протестируйте их.

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

Для вашего конкретного приложения, вместо того, чтобы просто объединять их вместе с помощью XOR, попробуйте объединить 32-битные значения таким образом, чтобы типичная хорошая хеш-функция объединила два независимых int. Т.е. умножить на простое и прибавить.

подсчет столкновений по размеру набора - отличная идея, спасибо!

martinus 25.12.2008 14:15

На основании вашего пояснения:

I have used long values in Java in such a way that the first 32 bit encoded an ID and the second 32 bit encoded another ID. Unfortunately Java's hash of long values just XORs the first 32 bit with the second 32 bits, which in my case led to very poor performance when used in a HashMap.

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

Вы явно задаете размер своих карт или используете значения по умолчанию? Проверка QAD, похоже, указывает на то, что HashMap<Long,String> начинается с 16-сегментной структуры и удваивается при переполнении. Это означало бы, что только младшие биты значений идентификатора фактически участвуют в выборе хэш-корзины. Вы можете попробовать использовать один из конструкторов, который принимает параметр начального размера, и создать свои карты с простым начальным размером.

С другой стороны, предложение Дейва Л. определить собственное хеширование длинных ключей позволит вам избежать проблемы зависимости с низким битом.

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

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