一、定义
哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
二、构造方法
哈希函数的构造原则是:函数本身便于计算、计算出来的地址分布均匀(即对任意K,f(K)对应不同地址的概率相等)。
1. 除留余数法
取关键字被某个不大于哈希表长m的数p除后所得的余数为哈希地址。即: H(key)=key MODE p,p<=m.(p的取值最好为素数)。 若冲突较多,可取较大的m和p值。 选择素数的原因 一个数模与素数的结果比较平均,比如说6为合数,有因子1,2,3,6。那么为该因子的倍数的数取模后都为0。7为素数,有因子1,7那么只有7的倍数的数取模才为0。
2. 平方取中法
当无法确定关键字中哪几位分布较均匀时,可以先求出关键字的平方值,然后按需要取平方值的中间几位作为哈希地址。 这是因为:平方后中间几位和关键字中每一位都相关,故不同关键字会以较高的概率产生不同的哈希地址。 例如对于关键key:123。1234^2=1522756,H(k)关键字的哈希地址为:227.
4.折叠法
这种方法是按哈希表地址位数将关键字分成位数相等的几部分(最后一部分可以较短),然后将这几部分相加,舍弃最高进位后的结果就是该关键字的哈希地址。具体方法有折叠法与移位法。移位法是将分割后的每部分低位对齐相加,折叠法是从一端向另一端沿分割界来回折叠(奇数段为正序,偶数段为倒序),然后将各段相加。 例如:key=12360324711202065,哈希表长度为1000,则应把关键字分成3位一段,在此舍去最低的两位65,分别进行移位叠加和折叠叠加,求得哈希地址为105和907。
5.直接定址法
取关键字或关键字的某个线性函数值为哈希地址。即: H(key)=key 或 H(key)=a*key+b 其中a、b为常数(这种hash函数叫做自身函数)。
举例1:统计1-100岁的人口,其中年龄作为关键字,哈希函数取关键字自身。查找年龄25岁的人口有多少,则直接查表中第25项。
地址 | 01 | 02 | 03 | … | 12 |
---|
年龄 | 1 | 2 | 3 | … | 12 | 人数 | 1000 | 2000 | 3000 | … | 2000 |
6.数字分析法
如果事先知道关键字集合,并且每个关键字的位数比哈希表的地址码位数多时,可以从关键字中选出分布较均匀的若干位,构成哈希地址。 例如,有1000个记录,关键字为10位十进制整数d1d2d3…d7d8d9d10,如哈希表长取1200,则哈希表的地址空间为:000~1199。假设经过分析,各关键字中 d3、d5和d7的取值分布较均匀,则哈希函数为:h(key)=h(d1d2d3…d7d8d9d10)=d3d5d7。 例如,h(3748597089)=457,h(9846372561)=432。就是找数字中分布均匀的数字。
三、哈希冲突的解决方法
1. 开放定址法,又称下标加1法
这种方法也称再散列法,其基本思想是:当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p1为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中。这种方法有一个通用的再散列函数形式: Hi=(H(key)+di)% m i=1,2,…,n 也就是产生冲突,依次查看其后的下一个桶,如果发现空位置插入新元素 其中H(key)为哈希函数,m 为表长,di称为增量序列。增量序列的取值方式不同,相应的再散列方式也不同。主要有以下三种: (1)线性探测再散列 (2)二次探测再散列 (3)伪随机探测再散列 缺点是:线性探测再散列容易产生“二次聚集”。当删除某个数据的时候,需要设置标记或者移动数据,否则会导致查找的中断。
2. 再哈希法
这种方法是同时构造多个不同的哈希函数: Hi=RH1(key) i=1,2,…,k 当哈希地址Hi=RH1(key)发生冲突时,再计算Hi=RH2(key)……,直到冲突不再产生。这种方法不易产生聚集,但增加了计算时间。
3. 链地址法;需要额外的空间;
这种方法的基本思想是将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。
4、公共溢出区
这种方法的基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表
|