如何散列unordered_map?

时间:2014-08-11 14:24:06

标签: c++ boost hash unordered-map

boost::hash具有大多数内置类型(包括容器)的散列函数。

但正如boost::hash_range function description中所述,范围的哈希算法

  

对元素的顺序很敏感,因此将它与无序容器一起使用是不合适的

因此boost::hashstd::unordered_map没有boost::unordered_map专门化。


问题是:

是否有一种“简单有效”的方法来散列unordered_map而无需从头开始重新实现哈希算法?

5 个答案:

答案 0 :(得分:6)

这里的问题是无保证项目甚至 之间的订单。
因此,对项目进行排序可能不适用于任意无序容器。您有两个选择:

  1. 对所有单个元素的哈希进行异或。这是最快的。
  2. 首先对容器的哈希进行排序,然后对这些哈希进行哈希处理。这可能会产生更好的哈希值。

答案 1 :(得分:1)

您当然可以将unordered_map转换为其他具有保证订单的数据结构,并使用该结构生成哈希值。

更好的想法可能是散列地图的每个单独元素,将这些散列放入vector,然后对散列进行排序和组合。请参阅示例How do I combine hash values in C++0x?以组合哈希值。

template<typename Hash, typename Iterator>
size_t order_independent_hash(Iterator begin, Iterator end, Hash hasher)
{
    std::vector<size_t> hashes;
    for (Iterator it = begin; it != end; ++it)
        hashes.push_back(hasher(*it));
    std::sort(hashes.begin(), hashes.end());
    size_t result = 0;
    for (auto it2 = hashes.begin(); it2 != hashes.end(); ++it2)
        result ^= *it2 + 0x9e3779b9 + (result<<6) + (result>>2);
    return result;
}

在随机向量上测试它会显示它总是返回相同的哈希值。

现在要使这个基本概念适用于unordered_map。由于unordered_map的迭代器返回pair,我们也需要哈希函数。

namespace std
{
    template<typename T1, typename T2>
    struct hash<std::pair<T1,T2> >
    {
        typedef std::pair<T1,T2> argument_type;
        typedef std::size_t result_type;

        result_type operator()(argument_type const& s) const
        {
            result_type const h1 ( std::hash<T1>()(s.first) );
            result_type const h2 ( std::hash<T2>()(s.second) );
            return h1 ^ (h2 + 0x9e3779b9 + (h1<<6) + (h1>>2));
        }
    };

    template<typename Key, typename T>
    struct hash<std::unordered_map<Key,T> >
    {
        typedef std::unordered_map<Key,T> argument_type;
        typedef std::size_t result_type;

        result_type operator()(argument_type const& s) const
        {
            return order_independent_hash(s.begin(), s.end(), std::hash<std::pair<Key,T> >());
        }
    };
}

查看实际操作:http://ideone.com/WOLFbc

答案 2 :(得分:0)

我认为你可能会混淆使用什么哈希。它用于标识元素以确定存储位置的键。两个等效元素应具有相同的值。

您是否正在尝试查看两个无序地图是否相同并将其存储在某种容器中?

无序地图的关键 - 那些是哈希的。实际上,容器将被称为hash_map,除了这样的容器已经存在。

但是好吧,假设你确实想要存储无序地图并进行比较以查看两个是否相同。那么你必须提出一个散列算法,它将返回相同的值,无论它包含的元素的位置如何。其所有元素(键和值)的校验和将是一种可能的方式。

另请注意,仅仅因为两个元素具有相同的哈希值,并不意味着它们是等效的。它只是意味着如果哈希值不同,它们肯定不等同。实际上,校验和通常用于验证数据,正是出于这个原因。错误的校验和证明数据无效,并且给出了一个好的公式,一个正确的公式使它很有可能,尽管不确定它是。

答案 3 :(得分:0)

我很好奇,因为您正在尝试哈希unordered_map以将其用作关键字,并且考虑到一旦您将unordered_map哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈。要改变它(除非你用它来创建一个新的密钥),将unordered_map转换为有序map的性能是否可以接受(然后,当然,散列有序的{{ 1}}并将其用作密钥)?或者这种方法的问题是您需要map提供更快的查找时间吗?

对于它的价值可能使用有序unordered_map(基于以下帖子中接受的答案map使用更多内存):

Is there any advantage of using map over unordered_map in case of trivial keys?

答案 4 :(得分:0)

您尚未指定任何性能要求,但如果您只是想要一个“快速而肮脏”的解决方案,无需代表您进行大量编码并利用boost::hash,则可以复制范围从unordered_mapvectorstd::sort向量的项目,然后将其传递给boost::hash_range

虽然不是最有效的解决方案,也不是您经常使用或使用多种元素的解决方案。

我首选的方法是unordered_map的特化,它保持内容的运行,最新散列 - 您不必传递所有元素并执行计算以获取当前值。相反,数据结构的成员应该反映散列,并在插入或删除元素时实时修改,并在需要时读取。