什么是哈希表
理想的查找是不经过任何的比较,一次存取就能得到想要查询的记录;要达到这样的目的就需要在记录的储存位置和它的关键字之间建立一个确定的关系f , 让每个关键字和结构中的一个唯一的地址相对应。在查找的时候,只需要对应关系f找到给定值K的像f(K),若结构中存在关键字和K相等,则必定在f(K)的储存位置上,由此不需要任何比较就能得到查询; 就好像数组一样,我们要找第一个数,调用a[0]就能得到第一个数, 当我们通过关键字来找的时候,通过一定的规则,把关键字和储存位置建立一个映射,就能通过数组的方式来访问关键字对应的记录;我们把这个对应关系f称为哈希函数,按这个思想建立的表称为哈希表
哈希函数是一个映像,因而哈希函数的设定很灵活,只要让任何关键字由哈希函数得到的哈希数值都在表长的允许范围内即可
对不同的关键字可能得到相同的哈希值,这种现象称为冲突, 有相同哈希值的关键词称为同义词, 冲突不能完全避免,只能尽可能的减少
哈希函数的构造
如果一个哈希函数能把一个关键字集合中的任意一个关键字,经哈希函数映像得到地址集合中的任何一个地址的概率是相等的,则称这个哈希函数的均匀的,这样的哈希函数才是“好”的哈希函数
常见的构建哈希函数的方法:
1.直接定址法:取关键字或者关键字的某个线性函数值作为哈希地址。即H(key) = a*key + b; 这种哈希函数叫做自身函数。我操,为啥寝室突然出现小强?可怕。 这种方法得到的地址集合和关键字集合的大小相同,因此不会发生冲突,但实际中用的比较少
2.平方取中间法:取关键字平方后的中间几位作为哈希地址。通常在不能知道全部关键词的情况下,用这种方法比较合适。平方后的中间几位数和数的每一位都相关,由此得到的哈希地址也是随机的,取的位数由表长决定
3.折叠法:把关键词分割为位数相同的几部分,最后一部分位数可以不同,然后取这几部分的叠加和作为哈希地址(舍去最高位的进位)。这种方法实用与关键字位数很多且关键字中每一位上数字分布大致均匀的时候。列如一个关键词为0442205864,当地址集合的大小不超过10000的时候, 这个时候可以构造一个四位数的哈希函数。分为以下两种情况
位移叠加:将分割后的每一部分的最低位对齐,然后相加,5864+4220+04=10088, 舍去最高位得到的哈希函数值是0088;
移位叠加:从一端向另一端沿分割界来回折叠,然后对齐最低位相加,5864+0224+04=6092, 相当于把每一部分之字型相加;
4.除留余数法:H(key) = key MOD p; p<=m, m是哈希表表长;最常用的一种方法,用这种方法的时候,对除数p的选择很重要,直接决定哈希函数的好坏;若除数p有质数因子pf,则所有含有pf因子的关键字的哈希地址均为pf的整数倍。 一般情况下选p为质数或不包含小于20的质因数的合数
5.随机数法:选择一个随机函数,取关键字的随机函数值作为哈希地址;
采取不同哈希函数的时候,应该考虑以下因素:计算哈希地址的时间,关键字长度,哈希表大小,关键字分布情况,记录的查找频率
冲突处理方法
冲突是指由关键字得到的哈希地址为j的位置上已存在记录,则处理冲突就是为该关键字的记录找到另一个“空”的哈希地址。在处理哈希冲突的时候,如果得到的另一个哈希地址任然冲突,则求下一个哈希地址,直到找到不发生冲突的哈希地址
1.开放地址法:Hi = (H(key) + di) MOD m, i=1,2,3,...m-1;di为曾量序列, m为哈希表长, H(key)为哈希函数;di的取值有以下几种
- di = 1,2,3,...,m-1,称为线性再探测散列
- di = 1*1,-1*1,2*2,-2*2,...,(m/2)*(m/2),-(m/2)*(m/2),称为二次再探测散列
- di = 伪随机数序列, 称为伪随机探测再散列
比如:取H(key) = key MOD 11, 哈希表已经如下
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
60 | 17 | 29 |
现在求38的哈希地址,会发现H(38) = 38 MOD 11 = 6 ,这个位置上已经有17了,所以要找下一个空的哈希地址H = (6+1) MOD 11 = 7, 依然被占据, 继续查找H = (6+2) MOD 11 = 8, 此时为空,则38的哈希地址为8. 由此可见关键字的哈希地址除了与关键字有关外,还与求哈希地址的先后顺序有关
2.再哈希法:Hi = RHi(key), RHi是不同的哈希函数,即在同义词产生地址冲突的时候,用另外一个哈希函数求哈希地址,直到冲突不再发生,这种方法不容易出产生聚集现象,但是会增加计算时间
3.链地址法:把所有关键字为同义词的记录储存在同一线性链表中。假设某哈希函数产生的哈希地址在[0,m-1]上,则设立一个指针型向量 Chain ChainHash[m]; 每一个分量的初始状态都是空指针,再链表中插入的位置可以在表头,或者表尾,或者中间,来保持同义词在同一链表中按关键词有序;
用该方法对{19,14,23,01,68,20,84,27,55,11,10,79}求哈希地址,取哈希函数为H(key) = key MOD 13
0 | ||||
1 | 1 | 14 | 27 | 79 |
2 | ||||
3 | 55 | 68 | ||
4 | ||||
5 | ||||
6 | 19 | 84 | ||
7 | 20 | |||
8 | ||||
9 | ||||
10 | 10 | 23 | ||
11 | 11 | |||
12 |
可以看出,对关键词除以13, 模相同的都在同一链表中,且链表中按照关键词排序;查找记录的时候,只需要找到关键词所在的链表,再遍历该链表就能找到关键词所在位置
原文地址:https://www.cnblogs.com/mr-stn/p/9048880.html