我想知道是否有任何散列函数可以在n个值上分配输入。分配当然应该是相当统一的。但有一个转折点。如果n的变化很小,则很少有元素会获得新的哈希值。最佳地,它应该在n个值上均匀地分割所有k,并且如果n增加到n + 1,则只有k / n-k /(n + 1)值必须移动到在新散列中均匀分布。显然有一个哈希只是简单地创建统一的值然后修改它将起作用,但这会移动很多哈希来填充新节点。这里的目标是尽可能少的值落入新的桶中。
答案 0 :(得分:3)
假设2 ^ {n-1}&lt; N <= 2 ^ n。然后有一个标准技巧,用于转换哈希函数H,它产生(至少)n个比特,产生一个从0到N的数字。
此技术的一些属性:
修改以添加关于&#34的其他评论;必须重新发布所有内容&#34;要求:可以考虑将上面的步骤3修改为&#34;从顶部开始,使用H(v)&#34;的前n位;代替。这减少了识别哪些元素需要重新定位的问题 - 因为它们将在桶中用于N的散列 - 尽管我不确定结果散列将具有相当好的冲突避免属性。它肯定会使这个过程变得更加脆弱 - 人们会想要证明H的选择有一些特殊的东西(最后几位不是&#39; t&#34;关键的&#34;它的碰撞避免特性)。
这是Python中的一个简单示例实现,以及一个简短的main
,它显示大多数字符串在正常碰撞时不会移动,并且大约一半的字符串在碰到2 ^ n边界时会被移动。请原谅我代码的任何特质 - Python是一门外语。
import math
def ilog2(m): return int(math.ceil(math.log(m,2)))
def hash_into(obj, N):
cur_hash = hash(obj)
mask = pow(2, ilog2(N)) - 1
while (cur_hash & mask) >= N:
# seems Python uses the identity for its hash on integers, which
# doesn't iterate well; let's use literally any other hash at all
cur_hash = hash(str(cur_hash))
return cur_hash & mask
def same_hash(obj, N, N2):
return hash_into(obj, N) == hash_into(obj, N2)
def bump_stat(objs, N):
return len([obj for obj in objs if same_hash(obj, N, N+1)])
alphabet = [chr(x) for x in range(ord('a'),ord('z')+1)]
ascending = alphabet + [c1 + c2 for c1 in alphabet for c2 in alphabet]
def main():
print len(ascending)
print bump_stat(ascending, 10)
print float(bump_stat(ascending, 16))/len(ascending)
# prints:
# 702
# 639
# 0.555555555556
答案 1 :(得分:0)
好吧,当你添加一个节点时,你会希望它填满,所以你实际上需要k /(n + 1)个元素从旧节点移动到新节点。
这很容易实现:
只需像往常一样为每个键生成哈希值。然后,将密钥k分配给[0,N)中的节点:
Let H(k) be the hash of k.
int hash = H(k);
for (int n=N-1;n>0;--n) {
if ((mix(hash,n) % (i+1))==0) {
break;
}
}
//put it in node n
因此,当您添加节点节点1时,它会从节点0中窃取一半的项目。 添加节点2时,它会窃取前2个节点中1/3的项目。 等等...
编辑:添加了mix()函数,以便对每个n不同地混合哈希值 - 否则当n不是素数时会出现非均匀性。