向量的良好散列函数

Mar*_*sen 21 c++ hash c++11

我有一些整数向量,我想在c ++ 11中的unordered_map中高效存储我的问题是:

如何最好地存储这些并优化.find查询?

我想出了以下的哈希:

class uint32_vector_hasher {
public:
  std::size_t operator()(std::vector<uint32_t> const& vec) const {
    std::size_t ret = 0;
    for(auto& i : vec) {
      ret ^= std::hash<uint32_t>()(i);
    }
    return ret;
  }
};
Run Code Online (Sandbox Code Playgroud)

然后将对象存储在unordered_mapI中然而有几个问题

  1. 哈希计算的频率是多少,只有一个,一些随机数或一些?
  2. 是否有意义创建一个包含==和哈希函数的包装器对象来记忆哈希并避免多次计算?

在进行性能分析时,我注意到我的cpu时间相当大,花费在无序地图上进行查找,这不是最佳的:(

Hol*_*ann 26

所以,当不想使用boost时,Michael Blurr的评论导致了以下哈希函数的实现:

std::size_t operator()(std::vector<uint32_t> const& vec) const {
  std::size_t seed = vec.size();
  for(auto& i : vec) {
    seed ^= i + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  }
  return seed;
}
Run Code Online (Sandbox Code Playgroud)

似乎工作.

  • 这是一个开始的种子。它会很快被异或操作(`^=`)改变。`vec.size()`(第 2 行)可能会更好,因为它考虑了更多的向量信息。我已经调整了回复。 (3认同)
  • std::accumulate 也可以应用 https://gcc.godbolt.org/z/vaK4h4dce (3认同)

Ric*_*ett 16

请尽可能与专家联系:http: //www.boost.org/doc/libs/release/doc/html/hash/reference.html#boost.hash_combine

  • 那么,为什么不使用`hash_range`来避免手动循环呢? (3认同)
  • @Orient请参阅http://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine (3认同)
  • @MartinKristiansen:boost也可以在多种平台上使用。即使您不希望使用boost,@ RichardPlunkett指向的`hash_combine()`函数也只是一种形式:`seed ^ = hash_value(v)+ 0x9e3779b9 +(seed &lt;&lt; 6 )+(种子&gt;&gt; 2);` (2认同)
  • @MartinKristiansen 公式中的幻数是否在理论上得到证实? (2认同)

I.A*_*Guy 11

HolKann 当前得票最高的答案中的哈希函数会导致大量向量发生高冲突率,这些向量都包含来自小型连续分布的元素。

为了解决这个问题,每个元素的位被均匀分布(算法取自Thomas Mueller 的答案)。

std::size_t operator()(std::vector<uint32_t> const& vec) const {
  std::size_t seed = vec.size();
  for(auto x : vec) {
    x = ((x >> 16) ^ x) * 0x45d9f3b;
    x = ((x >> 16) ^ x) * 0x45d9f3b;
    x = (x >> 16) ^ x;
    seed ^= x + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  }
  return seed;
}
Run Code Online (Sandbox Code Playgroud)

  • 好的。我最近也使用了托马斯·穆勒的答案。也许用 64 位版本来扩展您的答案? (3认同)