【问题标题】:Compute hash of map structure计算地图结构的哈希
【发布时间】:2019-10-03 07:44:20
【问题描述】:

我想计算一个整体的unordered_map 数据结构的哈希值。这样可以轻松比较两个 maps 是否包含完全相同的键值对。

显然,可以遍历包含的对,然后构建一个长字符串并对其进行哈希处理,但我可以想象有更好的方法来做到这一点。

目前,实际的哈希函数并不那么重要。我认为md5 可以。 sha 当然也是。

有什么建议吗?

【问题讨论】:

  • 我建议将所有键和所有值的哈希值组合在一起。理想情况下,允许您在添加/删除/更新地图条目时更新地图的哈希值。请注意,哈希的相等性并不能保证地图内容的相等性,但它仍然可以让您快速找出这些内容是否不同。
  • 是的,你当然是对的。我没有提到哈希冲突。

标签: c++ c++11 stl unordered-map


【解决方案1】:

您将需要一个可交换的 combine 函数,而 boost::hash_combine 故意不是,因此具有不同内部顺序的相等 unordered_map 具有相等的哈希值。为此,我建议对每个元素的哈希值进行异或运算。

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);
}

【讨论】:

  • 抱歉,我对模板和 lambdas 不太熟悉。首先,combine 函数的参数大概应该命名为 elem?之后如何调用此函数?在哪里找到模板?在头文件或源文件中?并且:是否同时考虑map-&gt;firstmap-&gt;second
  • @lukasl1991 哎呀。 combine被accumulate调用,在&lt;numeric&gt;中。我查了一下,std::hash 不是专门用于配对的,但 boost::hash 是。
  • 如果不熟悉模板和 lambda,就无法有效地使用现代 C++。
  • @Caleth 这似乎是我需要的。非常感谢!最后一个问题:我的无序映射包含在一个类 A 中,该类分为一个 A.cpp 和一个 A.hpp 文件。在哪里存储模板定义?什么是最佳实践?甚至在两个文件之外?
  • 模板需要在每个想要散列 UnorderedMaps 的翻译单元中可见,因此在它自己的标题中是一个常见的解决方案。它现在可以进入A.cpp,但稍后您可能想在其他地方引用它
【解决方案2】:

您可以尝试使用 boost 的 hash_combine() 来组合每个条目的哈希值。如果您不想使用 boost,您可以使用单个散列值的异或运算来最终生成一个组合散列值。

此外,您还可以阅读以下答案,该答案描述了如何在不使用哈希组合的情况下比较 2 个地图:

Link to answer

【讨论】:

  • 谢谢!我可能会对各个值进行异或运算。此外,我将看一下引用的答案:-)
  • 这仅适用于map,不适用于unordered_map
  • 好建议:-D