对于碰撞机会较低的一对整数,最小散列函数是什么?

时间:2016-06-20 09:28:16

标签: c++ hash

这是我到目前为止所做的:

struct pairhash {
public:
  inline std::size_t operator()(const std::pair<int, int> &c) const
  {
     int x = c.first;
     int y = c.second;
     return ((x+y)*(x+y+1)/2 + y); // Cantor's enumeration of pairs
  }
};

我需要使用这个哈希函数,这样我就可以将这对int放在这样的unordered_set中:

std::unordered_set< std::pair<int, int>,  pairhash> mySet;

编辑:忘了从这对中获得坐标。更新了代码。 编辑:删除了模板代码 - 错误地添加了它。

编辑:根据SO上的另一个类似答案更改了该功能,与Cantor对的枚举相关: hash function providing unique uint from an integer coordinate pair

编辑:不要求无碰撞(感谢Petr)。

3 个答案:

答案 0 :(得分:4)

如果您打算将其与unordered_set(以及大多数其他容器和算法)一起使用,则不需要散列函数是无冲突的。此外,哈希表和哈希函数的一般概念是它们允许冲突,它们只是期望碰撞很少。

cppreference says about the requirements for hashing

  
      
  1. 对于不相等的两个不同参数k1k2std::hash<Key>()(k1) == std::hash<Key>()(k2)的概率应为1.0/std::numeric_limits<size_t>::max()   非常小,接近koa
  2.   

答案 1 :(得分:2)

  

<强>更新

     

发布答案,发现问题已经更新。了解了我在下面的答案中提出的哈希方法的既定名称。

一般来说,如果2*sizeof(int) > sizeof(size_t),则不存在这样的功能。但是,假设您不会使用int类型的整个范围,您可以尝试构建一个没有碰撞的哈希函数,以获得2个整数的足够小的值。假设ab都有非负值,我可以提出以下函数:

size_t hashRangeStart(size_t n)
{
    return n*(n+1)/2; // == 1 + 2 + ... + n
}

size_t intPairHash(int a, int b)
{
    return hashRangeStart(a+b)+a;
}

这种方法背后的想法非常简单:

  • 成对的整数{ab}加起来相同的值n=a+b会产生一系列连续的哈希值,即intPairHash(a, b) == intPairHash(a+b, 0) + a
  • 和值nn+1的相邻值的哈希值范围,即intPairHash(0, a+1) == intPairHash(a, 0) + 1

将这种方法扩展到有符号值应该不会太困难。

答案 2 :(得分:1)

散列两个整数的一种简单方法是使用Knuth的散列:

size_t hash2(int i1, int i2)
{
    size_t ret = i1;
    ret *= 2654435761U;
    return ret ^ i2;
}