Вычислить хэш структуры карты

Я хотел бы вычислить хэш-значение структуры данных unordered_map в целом. Это позволяет легко сравнивать два map независимо от того, содержат ли они точно такие же пары ключ-значение или нет.

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

На данный момент фактическая хеш-функция не так важна. Думаю, md5 подойдет. sha тоже конечно.

Есть предложения?


person lukasl1991    schedule 16.05.2019    source источник
comment
Я предлагаю объединить хеш-значения для всех ключей и всех значений вместе. В идеале, таким образом, чтобы вы могли обновлять хэш карты во время добавления/удаления/обновления записей карты. Обратите внимание, что равенство хэшей не гарантирует равенство содержимого карт, но все же позволяет быстро узнать, отличается ли это содержимое.   -  person Daniel Langr    schedule 16.05.2019
comment
Да, вы правы, конечно. Я не упоминал хеш-коллизии.   -  person lukasl1991    schedule 16.05.2019


Ответы (2)


Вам понадобится функция коммутативного объединения, которая boost::hash_combine преднамеренно не используется, чтобы равные unordered_map с разным внутренним порядком имели одинаковые хэши. Для этого я предлагаю просто xoring хеш каждого элемента.

template<typename UnorderedMap>
std::size_t hash(const UnorderedMap & um)
{
    boost::hash<typename UnorderedMap::value_type> elem_hash;
    auto combine = [&](size_t acc, typename UnorderedMap::const_reference elem){ return acc ^ elem_hash(elem); };
    return std::accumulate(um.begin(), um.end(), 0, combine);
}
person Caleth    schedule 16.05.2019
comment
Извините, но я не так хорошо знаком с шаблонами и лямбда-выражениями. Во-первых, аргумент функции объединения, вероятно, должен называться elem? Как мне потом вызвать эту функцию? Где найти шаблон? В шапке или исходном файле? И: Учитывает ли это как map->first, так и map->second? - person lukasl1991; 17.05.2019
comment
@lukasl1991 Ой. combine вызывается методом аккумулирования, который находится в <numeric>. Я проверил, и std::hash не предназначен для пар, а boost::hash — есть. - person Caleth; 17.05.2019
comment
Вы не сможете эффективно использовать современный C++, если не знакомы с шаблонами и лямбда-выражениями. - person n. 1.8e9-where's-my-share m.; 17.05.2019
comment
@Caleth Кажется, это то, что мне нужно. Большое спасибо! Последний вопрос: моя неупорядоченная карта заключена в класс A, который разделен на файлы A.cpp и A.hpp. Где хранить определение шаблона? Что такое лучшая практика? Даже вне обоих файлов? - person lukasl1991; 17.05.2019
comment
Шаблон должен быть виден в каждой единице перевода, которая хочет хэшировать UnorderedMaps, поэтому в его собственном заголовке является распространенным решением. Он может быть помещен в A.cpp прямо сейчас, но позже вы можете сослаться на него в другом месте. - person Caleth; 17.05.2019

Вы можете попробовать использовать boost hash_combine() для объединения хэшей каждой записи. Если вы не хотите использовать повышение, вы можете использовать xor для отдельных значений хеш-функции, чтобы в конечном итоге получить комбинированное значение хеш-функции.

Кроме того, вы можете просмотреть приведенный ниже ответ, в котором описывается, как вы можете сравнить 2 карты без использования хэш-комбинации:

Ссылка на ответ

person Saket Sharad    schedule 16.05.2019
comment
Спасибо! Я, вероятно, исправлю отдельные значения. Кроме того, я посмотрю на упомянутый ответ :-) - person lukasl1991; 16.05.2019
comment
Это подходит только для map, а не unordered_map - person Caleth; 16.05.2019
comment
Хороший совет :-D - person lukasl1991; 17.05.2019