哈希表

Posted by Liao on 2020-05-16

一、简介

哈希表在待查关键字和它的存储位置之间,通过哈希函数,建立一个确定的对应关系。从而不必在关键字值之间的比较。

由图可以得出存储地址关键字值的对应关系是:存储地址 = 关键字值 - 32001,这个就是哈希函数。

但是,并不能保证每次都能构造出理想的哈希函数,因此要构建哈希表。哈希表中的存储地址就是哈希地址。

根据设定的哈希函数处理冲突的方法,将查找表中各元素存储在一段有限的连续空间中,就得到哈希表

二、构造哈希函数的方法

其实关键是找到哈希地址的各种方法,目的为了使冲突变少.

可以根据关键字的长度、哈希表的大小、计算哈希值的时间、关键字的分布情况、查找记录的频率,去选择哪种不同的哈希函数方法。

1. 直接定址法

根据关键字存储地址的关系构建哈希函数

2. 数字分析法

通常用于处理关键字位数比较大的情况(手机号码、身份证号码)。事先知道关键字的分布并且知道关键字的若干位分布比较均匀,就可考虑用这个方法。

例如身份证,截取后面不同的几位存储(例如5位),H(key) = key % 100000

3. 平方取中法

关键字较短,且不知道关键字的分布的情况

对关键字取平方,然后去中间的几位作为哈希地址。

如key = 1234, key^2 = 1522756,则哈希地址可以是227

4. 折叠法

适用于不知道关键字的分布,且关键字位数较多的情况

  • 移位叠加:由地位到高位分割,再加起来求和,舍去进位

    例如图书的ISBN 0-442-20586-4 -> 0442205864 -> 04 | 4220 | 5864 -> 5864 + 4220 + 04 = 10088 ->舍去进位1 -> 0088 = 88

  • 简界叠加: 方法同上,只是把分割的部分,从一端到另一端来回折叠相加,224 + 4685 + 4 = 4909 = 909

5. 除留余数法(常用)

对p必须为质数,如果不是质数,则哈希值会落到p倍数的地址上,增加了哈希冲突的可能。

6. 随机数法

取关键字的随机函数作为哈希地址。

H(key) = random(key)

三、处理哈希冲突的方法

哈希冲突是待插入哈希表的元素,按照给定的哈希函数求得的哈希地址已被占用,则按照一定的规则求下一个哈希地址,循环往复,直到找到可用的地址保存该元素

1.线性探测再散列

d = 1,2,3,4,5,6

2. 二次探测再散列

方法同上,只是d = 1^2, -1^2, 2^2, 2^-2 ……k^2,-k^2

二次探测的次数比一次的多,因此较高效

3. 链地址法

按照给定的哈希函数求得哈希地址相同的关键字,存储在同一线性表上,且链表按关键字有序

例如key = (67,84,18,26,34,28)

4. 公共溢出区法

把冲突的关键字放到公共溢出的区域

7,8,9规定为溢出区

四、在哈希表上查找元素

虽然通过哈希表能建立关键字值和存储位置上的映射,但由于冲突的存在,查找时还是需要进行关键字之间的比较,因此要把平均查找长度(ALS) 和 查找不成功时的比较次数作为衡量查找效率的依据。

根据待查关键字元素,按照给定的哈希函数,找出对应的哈希地址。

  • 若该地址上没有元素,则查找失败

  • 若有元素,则进行关键字值之间的比较

    • 若相等,则查找成功
    • 不相等,则按照处理冲突的方法求下一个可能存储的地址

key = 67, 67 % 7 = 4 查找次数1

key = 18 18 % 7 = 4 有冲突  (4+1) % 7 = 5 找到 查找次数为2

哈希通常不会用作数据库索引,因为哈希表不能范围查找和部分索引查找。一旦传入复合索引hash(user_id+name)就不可以了

但是,如果sql语句的查找条件不会变,或者没有范围查找或部分索引查找,可以用hash作为索引的数据结构,并且复杂度是O(1)