【问题标题】:What is a minimal hash function for a pair of ints that has low chance of collisions?对于发生冲突的可能性很小的一对整数,最小哈希函数是多少?
【发布时间】:2016-06-20 09:28:16
【问题描述】:

这是我目前所拥有的:

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

我需要使用这个哈希函数,这样我就可以将这对整数放在一个 unordered_set 中,如下所示:

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

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

编辑:根据关于 SO 的另一个类似答案更改了函数,与 Cantor 的配对枚举有关: hash function providing unique uint from an integer coordinate pair

编辑:无碰撞不是必需的(感谢 Petr)。

【问题讨论】:

  • 我有一种预感,如果size_tint,则没有这样的功能。
  • 这完全取决于您输入 w.r.t 的域。我相信您系统上std::size_t 的最大值/最小值。
  • 一般来说,哈希类型中的位数需要是元素类型的位数之和才能无冲突(如果两个元素值都可以是任意位模式)。然后哈希函数可以是位的简单串联。不过,您会遇到哈希表大小的问题。
  • 为什么你需要这个函数没有碰撞?
  • 域是指值的范围。因此,如果您的数字很小,它应该可以正常工作。但是,一旦您的人数增加一点,结果将不适合intsize_t。不要忘记ints 上的溢出是 UB,尤其是在开启优化的情况下。

标签: c++ hash


【解决方案1】:

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

cppreference says about the requirements for hashing:

  1. 对于两个不同的参数k1k2不相等,std::hash&lt;Key&gt;()(k1) == std::hash&lt;Key&gt;()(k2)应该的概率 非常小,接近1.0/std::numeric_limits&lt;size_t&gt;::max()

【讨论】:

  • 但是如果发生冲突,unordered_set 中会发生什么?我想这涉及到 unordered_set 的工作,但如果没关系,那我们为什么要实现散列函数呢?难道他们不能通过反映用户定义的数据类型等来使用其他通用方式吗...
  • @John,您应该阅读哈希表以获得完整答案。甚至wikipedia link sems 也能提供良好的归纳。简而言之——如果哈希值相等,unorderer_set 将使用标准比较运算符比较元素。但我们希望这种情况很少发生,以避免进行多次比较。
  • 如果您知道要存储多少数据,您可以将存储桶计数设置为相当高的值。仍然会有碰撞的机会,但应该非常少。
  • @John,对于“通用方式”——对于大多数标准类型,哈希函数确实存在于标准库中(我猜对于std::pair,您不需要编写自己的哈希函数,您可以使用标准的)。但是对于您自己的类的一般情况,只有您知道如何计算哈希。
  • 我对哈希表有所了解,但我不知道如何为 unordered_set 实现一个,因为每个哈希都是独立运行的,而且我们不存储任何结果等。
【解决方案2】:

更新

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

一般来说2*sizeof(int) &gt; 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;
}

这种方法背后的想法很简单:

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

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

【讨论】:

    【解决方案3】:

    哈希两个整数的简单方法是使用 Knuth 的哈希:

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

    【讨论】:

      猜你喜欢
      • 2017-08-24
      • 1970-01-01
      • 2020-08-14
      • 1970-01-01
      • 2020-07-03
      • 2019-03-17
      • 2019-03-25
      • 2014-10-02
      • 2018-11-05
      相关资源
      最近更新 更多