散列表

理想的查找方式就是不通过比较,就能根据所查关键码直接得到待查记录的存储位置。散列查找技术便是朝着这种方向建立的。散列表通过散列函数在关键码和存储位置之间建立一个对应关系,由关键码就可以直接获得存储地址。

散列(hash)函数也叫哈希函数,装填因子:表中将填入的记录数/哈希表的长度,则值越小,发生冲突的可能性越小。

散列表具体是:一些记录具体存储在一块通常用一个一维数组给出的连续存储空间中,根据记录关键码的散列函数值确定其存储地址。

散列技术的两个主要问题:

  1. 找一个好的散列函数,尽可能使记录在存储空间中分布均匀;同时,函数本身计算应当尽量简单
  2. 设计有效的处理冲突方法。

散列函数的构造方法:

基本原则:1.本身计算简单,容易从关键码计算得到地址范围内的值,计算量小速度快,否则会降低查找效率。2.分布均匀,使得冲突尽可能少,存储空间能得到有效利用。

1.直接定址法

关键码与地址之间存在线性函数关系:H(key)=a*key+b

2.数字分析法

可以取关键码的若干位的组合作为散列地址。如:关键码数字的第5位和第8位分布较均匀,则可取每个关键码这两位的组合作为存储地址。但是显然函数的构成和计算都会较复杂。

3.除留余数法

取适当的正整数p,H(key)=key%p

p通常为小于等于散列表表长的最大素数或不包含小于20的质因子的合数。

是一种最常用的构造散列函数的方法。

4.平方取中法

将关键码key平方,key^2中间几位作为散列地址的值。

5.折叠法

6.随机数法

H(key)=random(key),但这里使用伪随机数代替真正的随机数,以保证对同一关键码,存储和查找时都能对应同一个地址。

通常关键码长度不等时,使用伪随机数法构造哈希函数。

冲突的处理方法:

一、开放定址法:

散列表的地址对任何记录都是开放的,用开放定址法处理冲突所得的散列表叫做闭散列表(长度确定,总的可用地址有限),闭散列表的长度大于总的记录数,一旦发生冲突,后到的记录总能找到地址插入。

1.线性探测法

从当前地址开始,每次向后查找一个位置,直到查找到空的散列地址。

2.二次探测法

从当前地址开始,每次向:1^2,-1^2,2^2,-2^2,……探测空的地址空间

3.随机探测法

每次选择一个随机数获得下一个探测地址

4.再散列函数法

首先散列得到的地址若冲突,对得到的地址进行一个新的散列函数计算地址,可以事先设计一个散列函数序列进行处理。

5.建立公共溢出区

另外开辟一个空间,当发生冲突时,把同义词均顺序放入该空间中。

即:探测次数为1的关键码保存在基本的散列表中,探测次数超过1的关键码均保存在公共溢出区中,溢出区可使用单链表,也可以使用顺序表实现。

二、拉链法

散列表其实就是一个指针数组,将所有散列地址相同的记录存储在同一个单链表中,此单链表称为同义词单链表。单链表的头指针存储在散列函数中,以后每次得到一个地址,就在对应散列地址的单链表中加入一个该记录的节点。

这种方法构建的散列表称为开散列表,即由m条单链表组成,容量仅受内存容量的限制,因为单链表可以延伸。

总结:

散列表的构造过程:先开辟一个线性空间,如一维结构数组,再将关键字所代表的记录根据散列函数存储进去,如有冲突,则用解决冲突的方法寻找可用地址。

散列表的查找过程:对于给定的关键字k,根据散列函数求得散列地址,若地址上没有记录,则查找不成功,否则,比较散列表上该地址存储记录的关键字,若相等则查找成功,否则按照冲突处理方式查找下一个地址直到查找成功。

你可能感兴趣的:(数据结构)