📜  什么是哈希函数?如何选择一个好的哈希函数?

📅  最后修改于: 2021-04-22 07:05:40             🧑  作者: Mango

先决条件:哈希|设置1(简介)

什么是哈希函数?

给定大的电话号码转换为实用小整型值的函数。映射的整数值用作哈希表中的索引。简而言之,哈希函数将一个较大的数字或字符串映射为一个较小的整数,可用作哈希表中的索引。

良好的哈希函数是什么意思?

一个好的哈希函数应具有以下属性:

  1. 高效可计算。
  2. 应该统一分配密钥(每个密钥在每个表中的位置均等)

例如:对于电话号码,无效的哈希函数是采用前三位数字。更好的函数被认为是后三位数字。请注意,这可能不是最好的哈希函数。可能有更好的方法。

在实践中,我们经常可以使用启发式技术来创建性能良好的哈希函数。有关密钥分配的定性信息在此设计过程中可能会很有用。通常,哈希函数应取决于键的每个单个位,以便两个键的不同之处仅是一位或一组位(无论该组是在键的开始,结尾还是中间),或者存在于整个键中)散列为不同的值。因此,仅提取键的一部分的哈希函数是不合适的。类似地,如果两个键只是简单地数字或彼此的字符排列(例如139和319) ,则它们也应散列为不同的值。

两种启发式方法是按除法散列和乘以散列哈希,如下所示:

  1. mod方法:
    • 在这种创建哈希函数的方法中,我们通过将键的其余部分除以table_size来将键映射到表的插槽之一中。也就是说,哈希函数是
h(key) = key mod table_size 

i.e. key % table_size
  • 由于只需要一个除法运算,因此除法散列就相当快。
  • 当使用除法时,我们通常避免table_size的某些值(例如table_size)不应该是r的幂,因为如果table_size = r ^ p ,则h(key)只是key的p个最低位。除非我们知道所有低阶p位模式的可能性均等,否则最好将散列函数设计为依赖于密钥的所有位。
  • 已经发现,当表的大小为素数时,使用除法的最佳效果。但是,即使table_size是质数,也需要附加限制。如果r是计算机上可能的字符代码数,并且table_size是使r%table_size等于1的质数,则哈希函数h(key)= key%table_size就是以下字符二进制表示形式总和密钥mod table_size。
  • 假设r = 256并且table_size = 17,其中r%table_size即256%17 = 1。
  • 因此对于key = 37599 ,其哈希为
37599 % 17 = 12
  • 但是对于key = 573 ,其哈希函数也为
573 % 17 = 12
  • 因此可以看出,通过该哈希函数,许多键可以具有相同的哈希。这称为碰撞。
  • 不太接近2的幂的素数通常是table_size的不错选择。
  1. 乘法方法:
    • 在乘法方法中,我们将密钥k与范围为<的常数实数c相乘,并提取k * c小数部分
    • 然后,我们将此值乘以table_size m并得出结果的下限。它可以表示为
h(k) = floor (m * (k * c mod 1))
                     or
h(k) = floor (m * frac (k * c))
  • 在标准库math.h中可用的floor(x)函数产生实数x的整数部分,而frac(x)得到分数部分。 [frac(x)= x – floor(x)]
  • 乘法方法的一个优点是,m的值不是关键的,我们通常选择它是2的(M = 2 p表示一些整数p)的功率,因为我们可以很容易实现在大多数计算机的函数
  • 假设机器的字大小为w位,并且该键适合单个字。
  • 我们将c限制为s /(2 w )形式分数,其中s是0 w范围内的整数。
  • 参照图,我们首先将密钥乘以w位整数s = c * 2 w 。结果是2w位值
r1 * 2w + r0

where r1 = high-order word of the product
      r0 = lower order word of the product
  • 尽管此方法适用于常数c的任何值,但某些值比其他值更好。
c ~ (sqrt (5) – 1) / 2 = 0.618033988 . . .
  • 可能会运作良好。
  • 假设k = 123456, p = 14
  • m = 2 ^ 14 = 16384,而w = 32。
  • 根据Knuth的建议cs / 2 ^ 32形式分数。
  • 然后键* s = 327706022297664 =(76300 * 2 ^ 32)+ 17612864,
  • 因此r1 = 76300和r0 = 176122864。
  • r0的14个最高有效位产生值h(key)= 67。