直接根据高位将整数散列到N个大小大致相等的桶中(维持顺序)

Hash integers into N roughly equal sized buckets directly based on upper bits (maintaining order)

本文关键字:顺序 小大 高位 整数      更新时间:2023-10-16

最好是一种快速的方法。N = 2^b的情况非常简单。对于它,首先我会计算出我选择的类型中有多少比特:

typedef unsigned int type;
size_t size = sizeof(type) * 8;

然后,我将执行适当数量的比特的右移,以产生较高b比特的散列密钥。

type input = 0x657;
unsigned char b = 4;
unsigned char hash = input >> (size - b);

但是如果我想要N = 3呢?或者任何其他非2的幂?假设我的N总是适合一个unsigned char(所以它最多是256),那么散列一些input的最快方法是什么?同时保持bucket的范围差不超过+/-1,并保持input的高位的顺序,就像上面的函数一样。

对于32位值,用N进行64位乘法运算,并保留前32位。(类似地,对于其他大小,尽管如果您有64位值,乘法会变得更困难。)

这是一个基本的证明大纲。

很明显,这种映射是保序的;唯一的问题是每个桶中有多少个值。现在,考虑一些bucketj,并找到映射到该bucket的最小i。对于i落入桶j意味着Ni − j×232= m其中0 ≤ m < 232,但如果i是最小的值,则0 ≤ m < N。(否则,i−1也将落入桶j中。)

现在,定义w = ⌊232∕N⌋,相当于说Nw − 232= −m' where 0 ≤ m' < N。通过将这两个公式相加,我们发现Ni + Nw - j×232- 232= m−m';简化得到N(i+w)-(j+1)×232= m−m'−N < m−m' < N。这意味着i + wi + w + 1是映射到j + 1的最小值(取决于m − m'是否为负),这意味着存在映射到jww + 1值。由于任何j都是如此,因此我们可以肯定地说,只有两种bucket大小,其中一种是⌊232∕N⌋。离我在评论(现已删除)中所做的断言不远了,即另一个可能的bucket大小是⌈232∕N⌉

在上述证明中,232没有什么神奇之处;我可以使用任何值M。但这会使浓缩的校样更难阅读。