常见的六种哈希构造函数

文章目录

    • 相关概念介绍
    • 一、直接寻址法
    • 二、数字分析法
    • 三、折叠法
    • 四、平方取中法
    • 五、除留余数法
    • 六、随机数法

相关概念介绍

  • 哈希:
    Hash,一般翻译做散列、杂凑,或音译为哈希,是把任意长度的输入(又叫通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
  • 散列表:
    散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
  • 哈希冲突:
    由于哈希算法被计算的数据是无限的,而计算后的结果范围有限,因此总会存在不同的数据经过计算后得到的值相同,这就是哈希冲突。

一、直接寻址法

  • 介绍:取关键字或关键字的某个线性函数值为散列地址,即H(key)=key或者H(key)=a*key+b(a,b为常数)。
  • 举例:[‘A’,‘B’,‘D’,‘A’,‘C’,‘E’,‘F’,‘C’] ,求该字符数组里每个字符的出现次数(数组中只有大写字母)。
  • 分析:我们可以知道’A’-'Z’的ASCLL码是65-90,则哈希函数可以通过直接寻址法H(key)=key-‘A’(对应定义中的a=1,b=-‘A’即65),这样针对每一个key,都可以将它的H(key)值当成数组下标放在一个长度为26的int数组中统计长度
    假设字符数组为a,int数组为b。即b[a[i]-‘A’]++(i表示a数组的下标索引)。
  • 结果
    b[0]=2(代表A出现两次);b[1]=1(代表B出现一次),b[2]=2(代表C出现两次)…

二、数字分析法

  • 介绍:分析一组数据中相同位(个位,十位,百位…)的数字出现频率,如果该位数字出现结果较为集中,如果取其作为构造散列地址的依据则很容易出现哈希冲突,反之,如果该位数字出现结果较为平均,则取其作为构造散列地址的依据则不容易出现哈希冲突。
  • 举例:某公司招聘了一些实习生,其生日分别为[19990104,20000910,20000315,20001128,20001014,19990413,19990920,20000517],对其进行hash处理。
  • 分析
    如果取8位数作为散列地址,虽然很难出现哈希冲突,但是空间浪费很大,因此考虑只取其中几位作为散列地址,即能减少空间浪费又能降低哈希冲突的可能性,观察上面8组数据,前4位集中在1999,2000,如果取前4位则很容易出现哈希冲突,而后四位分布相对分散,不容易出现哈希冲突,因此取后四位比较符合。
  • 结果
    H(19990104)=104,H(20000910)=910,H(20000315)=315…

三、折叠法

  • 介绍:折叠法是把关键字值自左向右分成位数相等的几部分,每一部分的位数应与散列表地址的位数相同,只有最后一部分的位数可以短一些。把这些部分的数据叠加起来(去除进位),就可以得到关键字值的散列地址。
    有两种叠加方法:
    (1)移位法(shift floding):把各部分的最后一位对齐相加。
    (2)分界法(floding at the boudaries):沿各部分的分界来回折叠,然后对其相加。
  • 举例:key=1234791,散列地址为2位
  • 分析
    将key分成12,34,79,1四部分
    (1)移位法:12+34+79+1
    (2)分界法:12+43+79+1(即第偶数个加数和移位法反过来)
  • 结果
    (1)移位法:H(1234791)=35(相加为135,去除进位1)
    (2)分界法:H(1234791)=44(相加为144,去除进位1)

四、平方取中法

  • 介绍:当无法确定关键字中哪几位分布较均为时,可以求出关键字的平方值,然后按需要取平方值的中间几位作为散列地址。这是因为:平方后中间几位和关键字中每一位都有关,故不同关键字会以较高的概率产生不同的散列地址。
  • 举例:关键字序列:{3213,3113,3212,4312}。
  • 分析:
    3213^2=10323369
    3113^2=9690769
    3212^2=10316944
    4312^2=18593344
    取平方值中间4位为散列地址(3113的平方值前面补0凑成8位)
  • 结果
    H(3213)=3233,H(3113)=6907,H(3212)=3169,H(4312)=5933

五、除留余数法

  • 介绍:取关键字被某个不大于散列表表长m的数p除后的余数作为散列地址,即H(key)=key mod p(p<=m),该方法不仅可以直接对关键字取模,还可以在折叠,平方取中等方法后再取模。注意:p的选择很重要,一般选取满足条件(即p<=m)的最大质数或者m,如果取的不好容易产生哈希冲突。
  • 举例:关键字序列:{16,11,19,23,2,6,10},散列表表长为11。
  • 分析
    该散列表表长刚好为质数,直接选择p=11
  • 结果:
    H(16)=5, H(11)=0, H(19)=8, H(23)=1, H(2)=2, H(6)=6, H(10)=10

六、随机数法

  • 介绍:选择一随机函数,取关键字作为随机函数的种子,生成随机值作为散列地址,即H(key)=random (key),其中random为随机函数,通常用于关键字长度不同的场合。
  • 举例:key=123,随机函数为每位数字平方后连续相乘。
  • 分析
    随机函数的选择对于哈希冲突的概率很重要,这里只是简单的选择一个函数
  • 结果
    H(123)=36

你可能感兴趣的