散列表

  散列表
1  散列表与散列方法
前面讨论的表示查找表的各种结构,有一个共同点:记录在表中的位置和它的关键字之间不存在一个确定的关系,因此,查找的过程为给定值依次和关键字集合中各个关键字进行比较,查找的效率取决于和给定值进行比较的关键字个数。因此,用这类方法表示的查找表,其平均查找长度都不为零,不同表示方法的差别仅在于:和给定值进行比较的关键字的顺序不同。理想的情况是依据关键码直接得到其对应的数据元素位置,即要求关键码与数据元素间存在一一对应关系,通过这个关系,能很快地由关键码得到对应的数据元素位置。散列表与散列方法:选取某个函数,依该函数按关键码计算元素的存储位置,并按此存放;查找时,由同一个函数对给定值 key 计算地址,将 key 与地址单元中元素关键码进行比较,确定查找是否成功,这就是散列方法(杂凑法);散列方法中使用的转换函数称为散列函数(杂凑函数);按这个思想构造的表称为散列表(杂凑表)。
对于 n 个数据元素的集合,总能找到关键码与存放地址一一对应的函数。若最大关键为m,可以分配 m 个数据元素存放单元,选取函数 f(key)=key 即可,但这样会造成存储空间的很大浪费,甚至不可能分配这么大的存储空间。通常关键码的集合比散列地址集合大得多,因而经过散列函数变换后,可能将不同的关键码映射到同一个散列地址上,这种现象称为冲突(Collision),映射到同一散列地址上的关键码称为同义词。可以说,冲突不可能避免,只能尽可能减少。
所以,散列方法需要解决以下两个问题:
(1)构造好的散列函数
①所选函数尽可能简单,以便提高转换速度。
②所选函数对关键码计算出的地址,应在散列地址集中大致均匀分布,以减少空间浪费。
(2)制定解决冲突的方案。
2  常用的散列函数
对数字的关键字可有下列散列函数的构造方法,若是非数字关键字,则需先对其进行数字化处理。
1. 直接定址法
H(key) = key 或者 H(key) = a *key + b
即取关键码的某个线性函数值为散列地址,这类函数是一一对应函数,不会产生冲突。
此法仅适合于:地址集合的大小 = = 关键字集合的大小
2. 数字分析法
假设关键字集合中的每个关键字都是由 s 位数字组成(k1, k2, …, kn),分析关键字集中全体,并从中提取分布均匀的若干位或它们的组合作为地址。
此法仅适合于:能预先估计出全体关键字的每一位上各种数字出现的频度。
3.平方取中法
若关键字的每一位都有某些数字重复出现频度很高的现象,则先求关键字的平方值,以通过“平方”扩大差别,同时平方值的中间几位受到整个关键字中各位的影响。
此方法适合于:关键字中的每一位都有某些数字重复出现频度很高的现象。
4. 折叠法
若关键字的位数特别多,则可将其分割成几部分,然后取它们的叠加和为散列地址。可有:移位叠加和间界叠加两种处理方法。
(1)移位法:将各部分的最后一位对齐相加。
(2)间界叠加法:从一端向另一端沿各部分分界来回折叠后,最后一位对齐相加。
此方法适合于:关键字的数字位数特别多。
5. 除留余数法
H(key) = key MOD p p≤m (表长)
即取关键码除以 p 的余数作为散列地址。使用除留余数法,选取合适的 p 很重要,若散列表表长为 m,则要求 p≤m,且接近 m 或等于 m。p 一般选取质数,也可以是不包含小于 20质因子的合数。
通常,此方法用于对长度不等的关键字构造散列函数。
实际造表时,采用何种构造散列函数的方法取决于建表的关键字集合的情况(包括关键字的范围和形态),总的原则是使产生冲突的可能性降到尽可能地小。
3  处理冲突的方法
处理冲突的实际含义是:为产生冲突的地址寻找下一个散列地址。
1. 开放定址法
所谓开放定址法,即是由关键码得到的散列地址一旦产生了冲突,也就是说,该地址已经存放了数据元素,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将数据元素存入。
找空散列地址方法很多,下面介绍三种:
(1)线性探测法
H i =(Hash(key)+d i ) mod m ( 1≤i < m )
其中: Hash(key)为散列函数,m 为散列表长度,d i 为增量序列 1,2,……,m-1,且d i =i。
这种方法的特点是:冲突发生时,顺序查看表中下一单元, 直到找出一个空单元或查遍全表。
线性探测法可能使第 i 个散列地址的同义词存入第 i+1 个散列地址,这样本应存入第 i+1个散列地址的元素变成了第 i+2 个散列地址的同义词,……,因此,可能出现很多元素在相邻的散列地址上“堆积”起来,大大降低了查找效率。为此,可采用二次探测法改善“堆积”问题。
(2)二次探测法
H i =(Hash(key)±d i ) mod m
其中:Hash(key)为散列函数,m 为散列表长度,m 要求是某个 4k+3 的质数(k 是整数),
d i 为增量序列 1^2 ,-1^2 ,2^2 ,-2^2 ,……,q^2 ,-q^2 且 q≤(1/2)*m
这种方法的特点是:冲突发生时,在表的左右进行跳跃式探测,比较灵活。
(3)随机探测再散列
di 是一组伪随机数列,具体实现时,应建立一个伪随机数发生器,(如 i=(i+p) % m), 并给定一个随机数做起点。

2. 拉链法

这种方法的基本思想是将所有散列地址为 i 的元素构成一个称为同义词链的单链表,并将单链表的头指针存在散列表的第 i 个单元中, 因而查找、插入和删除主要在同义词链中进行。 链地址法适用于经常进行插入和删除的情况。
4  散列表的查找
查找过程和造表过程一致。假设采用开放定址处理冲突,则查找过程为:对于给定值 K, 计算散列地址 i = H(K),
若 r[i] = NULL ,则查找不成功
若 r[i].key = K ,则查找成功
否则求下一地址 Hi,直至 r[Hi] = NULL (查找不成功)或 r[Hi].key = K (查找成功)为止。
5  散列表的查找分析
散列表的查找过程基本上和造表过程相同。一些关键码可通过散列函数转换的地址直接找到,另一些关键码在散列函数得到的地址上产生了冲突,需要按处理冲突的方法进行查找。
在介绍的处理冲突的方法中,产生冲突后的查找仍然是给定值与关键码进行比较的过程。所以,对散列表查找效率的量度,依然用平均查找长度来衡量。
查找过程中,关键码的比较次数,取决于产生冲突的多少,产生的冲突少,查找效率就高,产生的冲突多,查找效率就低。因此,影响产生冲突多少的因素,也就是影响查找效率的因素。
影响产生冲突多少有以下三个因素:散列函数是否均匀;处理冲突的方法;散列表的装填因子。
分析这三个因素,尽管散列函数的“好坏”直接影响冲突产生的频度,但一般情况下,我们总认为所选的散列函数是“均匀的”,因此,可不考虑散列函数对平均查找长度的影响。就线性探测法和二次探测法处理冲突的例子看,相同的关键码集合、同样的散列函数,但在数据元素查找等概率情况下,它们的平均查找长度却不同。
散列表的装填因子定义为:α= 填入表中的元素个数/散列表的长度
α 是散列表装满程度的标志因子。由于表长是定值,α 与“填入表中的元素个数”成正比,
所以,α 越大,填入表中的元素较多,产生冲突的可能性就越大;α 越小,填入表中的元素较
少,产生冲突的可能性就越小。
实际上,散列表的平均查找长度是装填因子 α 的函数,只是不同处理冲突的方法有不同的函数。
散列方法存取速度快,也较节省空间,但由于存取是随机的,因此,不便于顺序查找。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值