【问题标题】:hash function for a vector of pair<int, int>pair<int, int> 向量的散列函数
【发布时间】:2014-07-14 14:53:32
【问题描述】:

我正在尝试为矢量> 实现一个unordered_map。从there's no such default hash function开始,我试着想象一个我自己的功能:

struct ObjectHasher
{
  std::size_t operator()(const Object& k) const
  {
    std::string h_string("");
    for (auto i = k.vec.begin(); i != k.vec.end(); ++i)
    {
      h_string.push_back(97+i->first);
      h_string.push_back(47); // '-'
      h_string.push_back(97+i->second);
      h_string.push_back(43); // '+'
    }
    return std::hash<std::string>()(h_string);
  }
};

主要的想法是改变整数列表,比如 ( (97, 98), (105, 107) ) 变成像 "a-b+ik" 这样的格式化字符串 并通过 hash () 计算其哈希值。我选择 97、48 和 43 数字只是为了让哈希字符串在我的测试期间可以轻松地显示在终端中。

我知道这种函数可能是一个非常幼稚的想法,因为一个好的哈希函数应该是快速并且抗碰撞能力强。好吧,如果给 push_back() 的整数大于 255,我不知道会发生什么……那么,您如何看待以下问题:

  • (1) 我的函数是否适用于大整数?
  • (2) 我的功能适用于所有环境/平台吗?
  • (3) 我的函数是否太慢而不能成为哈希函数?
  • (4) ...你有什么更好的吗?

【问题讨论】:

  • 编写一个好的 hast 函数可能非常困难。使用 std::map 而不是散列函数较差的 unordered_map 可能会更好。

标签: c++ vector hash


【解决方案1】:

您所需要的只是一个“散列”整数的函数。你可以从 boost 中窃取这样的功能:

template <class T>
inline void hash_combine(std::size_t& seed, const T& v)
{
    std::hash<T> hasher;
    seed ^= std::hash<T>(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}

现在你的功能很简单:

struct ObjectHasher
{
  std::size_t operator()(const Object& k) const
  {
    std::size_t hash = 0;
    for (auto i = k.vec.begin(); i != k.vec.end(); ++i)
    {
      hash_combine(hash, i->first);
      hash_combine(hash, i->second);
    }
    return hash;
  }
};

【讨论】:

  • 这只是一种已知的算法,可以合理地分布散列值(将单个位差异分散到尽可能多的输出位上)。 Knuth 证明了接近 (2^32 / [(sqrt(5)+1)/2]) 的素数效果最好。您可以使用许多其他散列算法。
  • @DavidSchwartz 这不会为包含列表 (1, 2) 的映射与包含列表 (2, 1) 的映射产生相同的哈希,因为 xor 是关联的?
  • @mclaassen 不,因为种子也以非关联的方式使用。
  • @DavidSchwartz 哦,好吧,我明白了,您还使用最后一个值来计算哈希值,然后得到 XORed
  • std::hash&lt;T&gt; hasher; 似乎没有任何作用,但大概你的意思是下面的行应该调用operator() 而不是试图将散列值传递给其构造函数的语法错误;很容易忘记它不是函数重载,而是函数对象。
【解决方案2】:

与其他哈希函数相比,此函数可能非常慢,因为它使用动态内存分配。另外std::hash&lt;std::string&gt; 不是一个很好的哈希函数,因为它非常通用。对所有整数进行 XOR 并使用 std::hash&lt;int&gt; 可能会更好。

【讨论】:

  • 我不认为将所有数字异或在一起工作,会有非常高的冲突率。
  • 如果sizeof (int) == sizeof(size_t) 这几乎是你能得到的最好的。它也非常快。
  • @TNA XORing 所有的数字都是一样的,不管你做的顺序是什么。所以它不会捕捉到数字 5 是数字对中的第一个或第二个数字之间的区别,或者是否5 与一个数字与另一个数字配对
【解决方案3】:

这是一个完全有效的解决方案。哈希函数只需要一个字节序列,通过将元素作为字符串连接在一起,您就可以提供地图的唯一字节表示。

当然,如果您的地图包含大量项目,这可能会变得不守规矩。

【讨论】:

    猜你喜欢
    • 2020-10-22
    • 1970-01-01
    • 1970-01-01
    • 2019-02-20
    • 1970-01-01
    • 2020-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多