完美的哈希函数

gre*_*ghz 19 hash hashtable perfect-hash

我正在尝试散列值

10, 100, 32, 45, 58, 126, 3, 29, 200, 400, 0
Run Code Online (Sandbox Code Playgroud)

我需要一个函数,将它们映射到一个大小为13的数组,而不会导致任何冲突.

我花了几个小时思考这个并用谷歌搜索,无法解决这个问题.我还没有接近可行的解决方案.

我将如何找到这种哈希函数?我玩过gperf,但我真的不明白它,我无法得到我想要的结果.

tob*_*ies 24

如果你知道确切的密钥,那么生成一个完美的哈希函数是微不足道的 -

int hash (int n) {
  switch (n) {
    case 10:   return 0;
    case 100:  return 1;
    case 32:   return 2;
    // ...
    default:   return -1;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 这实际上是一个表格搜索.散列函数的一个好处应该是:它允许比表搜索更快地评估命中/未命中. (4认同)
  • @Craig这明显比表搜索更快,即使使用`gcc -O0`这比我机器上的简单线性表搜索快5倍,使用`-O2`线性搜索需要一秒钟和'时间'报告对于100万次查找,总时间为"0.00"......与使用"-O0"的速度超过1亿次迭代的接受答案几乎完全相同,并且在-0.2秒内在0.2s内完全相同.如果密钥存在/有效,那么你需要做的就是这个哈希函数更快 - "hash(n)== - 1"不需要内存访问...你可以安全地添加具有剩余功能的密钥完善. (3认同)
  • 您的哈希可能比数据表查找更快,但这不是我的意思.澄清一下:你的哈希可能适用于这个小数据集,同意.但对于大小为n的数据集,您的哈希值为O(n),而接受的答案为O(1).散列函数的要点是提供O(1)解.因此,在原始问题的数据集的特定情况下,您的解决方案是令人满意的,但在"为数据集找到完美的哈希函数"(特别是大于某个阈值)的更一般情况下,您的答案是'适合. (3认同)

Dig*_*oss 11

找到一个

我尝试了一些东西,发现一个半手动:

(n ^ 28) % 13
Run Code Online (Sandbox Code Playgroud)

半手动部分是我用于测试具有一系列参数的候选函数的以下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
Run Code Online (Sandbox Code Playgroud)


Cra*_*een 5

在某些平台(例如嵌入式)上,模运算很昂贵,因此% 13可以更好地避免.但是AND低阶位的操作是便宜的,并且相当于2的幂的模.

我尝试编写一个简单的程序(用Python)来搜索11个数据点的完美哈希,使用简单的形式,例如((x << a) ^ (x << b)) & 0xF(其中& 0xF相当于,例如% 16,给出0..15范围内的结果).我能够找到以下无冲突哈希,它给出了一个范围为0..15的索引(表示为C宏):

#define HASH(x)    ((((x) << 2) ^ ((x) >> 2)) & 0xF)
Run Code Online (Sandbox Code Playgroud)

这是我使用的Python程序:

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()
Run Code Online (Sandbox Code Playgroud)