无论是顺序文件的顺序查找法和折半查找法、索引文件查找法以及在B-树B+树中进行的查找方法,都是基于关键字值比较的查找方法,查找的时间效率主要取决于查找过程中进行的比较次数。

那么,能否有一种不经过任何关键字值的比较或者经过很少次的关键字值的比较就能够达到目的方法?

答案是肯定的,要需要建立记录的关键字与记录的存储位置之间的关系,这就是本文要说的散列文件

基本概念

1、散列函数

A = H(k)
其中,k 为记录的关键字,H(k)称为散列函数,或哈希(Hash)函数,或杂凑函数。函数值A为k对应的记录在文件中位置。

2、散列冲突
对于不同的关键字ki与kj,经过散列得到相同的散列地址,即有
H(ki) = H(kj)
这种现象称为散列冲突

3、散列文件

根据构造的散列函数与处理冲突的方法将一组关键字映射到一个有限的连续地址集合上,并以关键字在该集合中的“象”作为记录的存储位置,按照这种方法组织起来文件称为散列文件哈希文件 ,或称杂凑文件 ;建立文件的过程称为哈希造表或者散列,得到的存储位置称为散列地址或者杂凑地址。

散列函数的构造

1、原则

1、散列函数的定义域必须包括将要存储的全部关键字;若散列表允许有m个位置时,则函数的值域为[0 … m–1](地址空间);
2、利用散列函数计算出来的地址应能尽可能均匀分布在整个地址空间中;
3、散列函数应该尽可能简单,应该在较短的时间内计算出结果;

2、建立散列文件的步骤

1、确定散列的地址空间(地址范围);
2、构造合适的散列函数;
3、选择处理冲突的方法。

3、散列函数的构造方法

1、 直接定址法
2、 数字分析法
3、 平方取中法
4、叠加法
5、基数转换法
6、除留余数法

除留余数发如下:
H(k) = k MOD p
其中,若m为地址范围大小(或称表长),则p可为小于等于m的素数。

冲突的处理方法

所谓处理冲突,是在发生冲突时,为冲突的元素找到另一个散列地址以存放该元素。如果找到的地址仍然发生冲突,则继续为发生冲突的这个元素寻找另一个地址,直到不再发生冲突。

冲突的处理方法有如下几种:

开放地址法(闲散列方法)

文件(五)——散列(Hash)文件及其基本操作_线性探测法

开放地址法有如下特点:
1、“线性探测法”容易产生元素“聚集”的问题。
2、“二次探测法”可以较好地避免元素“聚集”的问题,但不能探测到表中的所有元素(至
少可以探测到表中的一半元素)。
3、只能对表项进行逻辑删除(如做删除标记),而不能进行物理删除。使得表面上看起来很满的散列表实际上存在许多未用位置。

聚集指的是散列地址不同的元素争夺同一个后继散列地址的现象

产生聚集的主要原因如下:
1、散列函数选择得不合适;
2、负载因子过大;

负载因子是衡量散列表的饱满程度的指标,计算公式如下:

文件(五)——散列(Hash)文件及其基本操作_散列函数_02


一般情况下,a<1,a越大,散列表越满。

再散列法

Di = Hi(k) , i=1, 2, 3, …
其中,Di为散列地址,Hi(k)为不同的散列函数,
即在散列的基础上再散列一次。

链地址法

将所有散列地址相同的记录链接成一个线性链表。若散列范围为[0…m-1],则定义指针数组bucket[0…m-1]分别存放m个链表的头指针,如下图:

文件(五)——散列(Hash)文件及其基本操作_链地址法_03


该方法的特点如下:

1、处理冲突简单,不会产生元素“聚集”现象,平均查找长度较小 ;

2、适合建立散列表之前难以确定表长的情况 ;

3、建立的散列表中进行删除操作简单;

4、由于指针域需占用额外空间,当规模较小时,不如“开放地址法”节省空间。