Day_11,Hash表的核心Hash函数的研究

在一个Hash表中,一个好的Hash函数决定了这个Hash表的工作效率,今天就来研究一下Hash函数。
Hash函数可以简单的划分为如下几类:
1、 加法Hash; 2、 位运算Hash; 3、 乘法Hash; 4、 除法Hash; 5、全域哈希法;

1、加法Hash
加法Hash就是把输入元素一个一个的加起来构成最后的结果。标准的加法Hash的构造如下:

int additiveHash(string key, int prime)
{
    int hash = key.length();

    for (int i = 0; i < key.length(); i++)
    {
        hash += key[i];
    }

    return (hash % prime);
}

2、位运算Hash
位运算Hash通过利用各种位运算(常见的是移位和异或)来充分的混合输入元素,先移位,然后再进行各种位运算是这种类型Hash函数的主要特点。标准的位运算Hash的构造如下:

int rotatingHash(string key, int prime) {

    int hash = key.length();

    for (int i = 0; i < key.length(); i++)
    {
        hash = (hash<<4>>28)^key[i];
    }

    return (hash % prime);
}

3、乘法Hash
乘法Hash利用了乘法的不相关性(乘法的这种性质,最有名的莫过于平方取头尾的随机数生成算法,虽然这种算法效果并不好)。标准的乘法Hash的构造如下:

int multiHash(string key, int prime) {

    double hash = 0;

    for (int i = 0; i < key.length(); i++)
    {
        hash += key[i];
    }
    int temp = floor((2<<14)*(hash*(sqrt(5)-1)/2 - floor(hash*(sqrt(5)-1)/2)));

    return (temp % prime);

}

4、除法Hash
除法Hash就是把元素k对一个整数m取余,将k映射到对应的一个地址,标准的除法Hash如下

int divisionHash(int key)
{
    int hash = key%23;

    return hash;
}

5、 全域哈希法
在向哈希表中插入元素时,如果所有的元素全部被哈希到同一个桶中,此时数据的存储实际上就是一个链表,那么平均的查找时间为 Θ(n) 。而实际上,任何一个特定的哈希函数都有可能出现这种最坏情况,唯一有效的改进方法就是随机地选择哈希函数,使之独立于要存储的元素。这种方法称作全域哈希(Universal Hashing)

为什么是prime:

在上面的许多例子里都看到了一个东西 prime (素数),这个素数在代码里面的作用都是将预算内宿限制在prime这个范围内,相信读者都明白。但是为什么是prime?
证明:设 key%m = key - xm,即key减掉m的某个倍数x,剩下比m小的部分就是key除以m的余数。显然,x等于key/m的整数部分,以floor(key/m)表示。假设key和m有公约数g,即key=ag, m=bg, 则 key - xm = key - floor(key/m)m = key - floor(a/b)m。由于0 <= a/b <= a,所以floor(a/b)只有a+1中取值可能,从而推导出key%m也只有a+1中取值可能。a+1个球放在m个盒子里面,显然不可能做到均匀。
下图为出自《算法导论的解释》
在这里插入图片描述
具体的例子详见https://blog.csdn.net/Ilozk/article/details/90762541

最小完美哈希函数

在满足完美哈希(不会产生冲突(单射))的前提下,key值数量(假设为n)和哈希表中槽的数量(假设为m)相等,即 m = n,此种哈希函数被称为最小完美哈希函数(其实相当于数学中双射的概念)

设计完美哈希的基本思想是利用两级的哈希策略,而每一级上都使用全域哈希(Univeral Hashing)。

在这里插入图片描述

第一级与使用链接技术(chaining)的哈希表基本上是一样的,利用从某一全域哈希函数族中随机选择的一个函数 h ,将 n 个关键字哈希到 m 个槽中。

而此时,不像链接技术中对槽使用链表结构,而是采用一个较小的二次哈希表 Sj ,与其相关的哈希函数为 hj 。通过随机的选取哈希函数 hj ,可以确保在第二级上不出现哈希冲突。

如果利用从一个全域哈希函数族中随机选择的哈希函数 h,将 n 个关键字存储在一个大小为 m = n2 的哈希表中,那么出现碰撞的概率小于 1/2 。

为了确保第二级上不出现哈希冲突,需要让哈希表 Sj 的大小 mj 为哈希到槽 j 中的关键字数 nj 的平方。mj 对 nj 的这种二次依赖关系看上去可能使得总体存储需求很大,但通过适当地选择第一次哈希函数,预期使用的的总存储空间仍为 O(n)。

如果关键字的数量 n 等于槽的数量 m ,则该哈希函数称为最小完美哈希函数(Minimal Perfect Hash Function)。

下面是几篇关于完美Hash的博客,改日继续研究。困zzzZZZ
https://www.cnblogs.com/eve-walle/archive/2012/09/17/2688914.html
http://blog.chinaunix.net/uid-14789604-id-84624.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值