我正在尝试对这些值进行哈希处理
10, 100, 32, 45, 58, 126, 3, 29, 200, 400, 0
我需要一个函数,将它们映射到一个大小为13的数组中而不会引起任何碰撞。我花了几个小时思考并搜索,但无法解决。我还没有接近可行的解决方案。
我该如何找到这种类型的哈希函数?我尝试使用gperf进行测试,但我不太理解它,也无法获得我要找的结果。
我正在尝试对这些值进行哈希处理
10, 100, 32, 45, 58, 126, 3, 29, 200, 400, 0
我需要一个函数,将它们映射到一个大小为13的数组中而不会引起任何碰撞。如果您知道确切的键,那么生成完美的哈希函数是微不足道的 -
int hash (int n) {
switch (n) {
case 10: return 0;
case 100: return 1;
case 32: return 2;
// ...
default: return -1;
}
}
gcc -O0
下,我的机器上它比简单的线性表查找快了5倍,使用 -O2
时,线性搜索需要超过一秒钟,而1百万次查找的总时间为 0.00
。它几乎与已接受的答案在100亿次迭代中的速度相同,在 -O0
下甚至更快,并且在 -O2
内部只有0.2秒的差异。如果你只需要判断键是否存在/有效,则该哈希函数更快--hash(n)==-1
不需要访问内存... 并且你可以通过该函数安全地添加键而保持完美。 - tobyodaviesO(n)
,而通常是O(1)
或O(log(n))
。 - tobyodavies我尝试了几个方法,最终半自动找到了一个:
(n ^ 28) % 13
半自动化部分是我使用的以下Ruby脚本,用于测试具有一系列参数的候选函数:
t = [10, 100, 32, 45, 58, 126, 3, 29, 200, 400, 0]
(1..200).each do |i|
t2 = t.map { |e| (e ^ i) % 13 }
puts i if t2.uniq.length == t.length
end
((x << a) ^ (x << b)) & 0xF
(其中& 0xF
等同于% 16
,例如在范围0..15内给出结果)。我能够找到以下无冲突哈希,它可以在0..15范围内提供索引(表示为C宏):#define HASH(x) ((((x) << 2) ^ ((x) >> 2)) & 0xF)
data = [ 10, 100, 32, 45, 58, 126, 3, 29, 200, 400, 0 ]
def shift_right(value, shift_value):
"""Shift right that allows for negative values, which shift left
(Python shift operator doesn't allow negative shift values)"""
if shift_value == None:
return 0
if shift_value < 0:
return value << (-shift_value)
else:
return value >> shift_value
def find_hash():
def hashf(val, i, j = None, k = None):
return (shift_right(val, i) ^ shift_right(val, j) ^ shift_right(val, k)) & 0xF
for i in xrange(-7, 8):
for j in xrange(i, 8):
#for k in xrange(j, 8):
#j = None
k = None
outputs = set()
for val in data:
hash_val = hashf(val, i, j, k)
if hash_val >= 13:
pass
#break
if hash_val in outputs:
break
else:
outputs.add(hash_val)
else:
print i, j, k, outputs
if __name__ == '__main__':
find_hash()
Bob Jenkins也有这样的程序:http://burtleburtle.net/bob/hash/perfect.html
除非你非常幸运,否则对于给定的数据集,没有“好的”完美哈希函数。完美哈希算法通常在键上使用简单的哈希函数(使用足够的位数使其无冲突),然后使用表来完成它。
以下是一些准解析性的胡言乱语:
在你的数字集合中,总共有11个数字,其中3个是奇数,8个是偶数。看最简单的哈希形式 - %13 - 会给你以下哈希值: 10 - 3, 100 - 9, 32 - 6, 45 - 6, 58 - 6, 126 - 9, 3 - 3, 29 - 3, 200 - 5, 400 - 10, 0 - 0
当然,由于冲突太多,这是不可用的。需要更复杂的方法。
为什么要说显而易见的事情? 考虑到数字如此之少,任何复杂的算法 - 或者说是“不那么简单”的算法 - 都可能比switch语句慢,或者(我更喜欢的)直接搜索一个大小为11的unsigned short/long向量,并使用匹配的索引。
为什么要使用向量搜索?