使用Hash查找,首先要创建一张Hash表。
- Hash表,又叫做散列表,是根据给定的关键字来计算出关键字在表中的地址的数据结构。也就是说,Hash表建立了关键字(自变量)和存储地址(应变量)之间的一种直接映射关系。
如何建立它们之间的关系?还有这种关系一定是一对一的吗?
hash表表长应该多大?
装填因子
hash表的装填因子一般记作 α,可以理解为一个表的装满程度
α = (表中记录数n) / (hash表长m)
α 一般在 0.7~0.8之间
所以一般设 hash表长 m = n/α
Hash表创建的两个主要问题:Hash函数的构造和冲突的解决。
- Hash函数:一个把查找表中的关键字映射成该关键字对应的地址的函数,
记作Hash(key)=Addr; - Hash函数可能会把两个或以上的不同关键字映射到同一地址,称这种情况为“冲突”,这些发生碰撞的不同关键字成为同义词。
常用的Hash函数构造方法:
直接地址法
直接取关键字的某个线性函数值为hash地址
H(key) = a*key + b
保留除数法(除留余数法)
假定hash表长m,取一个不大于m但最接近或等于m的质数p
H(key) = key % p
该方法的关键在于选好p,尽可能减少冲突的可能性
平方取中法
取关键字的平方值的中间几位作为hash地址。具体取多少根据实际情况而定。
eg.
12342 = 1522756,取中间三位227作为hash地址
23452 = 5499025,取中间三位990最为hash地址
叠加法
将关键字分割成位数相同的几部分(最后一部分的位数可能短一些),然后取这几部分的叠加和作为hash地址。
eg.
关键字 1234567890,设hash表表长为3位,则将关键字分为4组
123 | 456 | 789 | 0 ,然后求叠加和 123+456+789+0 = 1368,取后3位368作为hash地址
常用的处理冲突的方法:
开放地址法
将产生冲突的hash地址作为自变量,通过某种冲突解决函数得到一个新的空闲的hash地址。
- ①线性探查法
发生冲突时,顺序查看表中下一个单元,直到找出一个空闲单元。
eg. H(key) = key % 8
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
key | 9 | 10 | 11 | 19 | 27 |
- ②二次探查法(平方探查法)
设发生冲突的地址位d,平方探测法得到的新的地址序列位d+12,d-12,d+22,d-22…
eg. H(key) = key % 8
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
key | 9 | 10 | 11 | 19 | 27 |
链地址法
发生冲突时,将具有相同hash地址的对象以链表的形式存储,通过对象内部的指针可以查询到下一个具有相同hash地址的对象。简单说就是,将产生冲突的值以链表的形式连起来。
Hash查找的过程
- 给定带查找的关键字key
- 根据hash函数计算出hash地址,检测该位置有无数据
- 没有,表明该关键字不存在,返回失败
- 有,检测该数据是否等于key
- 等于,返回key所在位置
- 不等于,按照给定的冲突处理方法计算下一个hash地址,再去执行上述过程
这里使用保留除数法构建Hash表,使用线性探查法处理冲突。
程序运行结果:
实现代码:
#