1.桶数组
散列表的桶数组是一个大小为N的数组A,其中A的每个单元可看作一只“桶”,整数N表示数组的容量,如果关键字为整数,且
均匀地分散在范围[0,N-1]中,这个桶数组就是所需要的数组。关键字为K的元素e被简单地插入到桶A[k]中。
2.散列函数
散列函数将字典中的每个关键字k映射到区间[0,N-1]内的一个整数,其中N是这个散列表的桶数组的容量。这个方法的主要思想是利用散列函数值h(k)作为桶数组A的下标,而不是使用关键字k,即将数据项(k,e)存储在桶A[h(k)]中。 对于散列函数性能的评估有两个行为组成:一个是将关键字映射到一个整数上,称为散列编码;一个是将散列编码映射到桶数组下标内的一个整数上,称为压缩映射。
关键字——>散列编码——>压缩映射到桶数组区间
3.压缩映射
1)除法散列法
h(k)=|k| mod N;
如果N为素数,则该方法有助于"扩散"散列值的分布;如果N不是素数,关键字分布中的模式在散列编码分布中出现重复的可能性更大,因而会有冲突。
2)MAD方法(乘加与除方法)
h(k)=|ak+b| mod N;其中N是素数,a,b是在确定压缩函数时随机选取的非负整数,满足a mod N 不等于0.
3)余数法:先估计整个哈希表中的表项目数目大小。然后用这个估计值作为除数去除每个原始值,得到商和余数。用余数作为哈希值。因为这种方法产生冲突的可能性相当大,因此任何搜索算法都应该能够判断冲突是否发生并提出取代算法。
4)折叠法:这种方法是针对原始值为数字时使用,将原始值分为若干部分,然后将各部分叠加,得到的最后四个数字(或者取其他位数的数字都可以)来作为哈希值。
5)基数转换法:当原始值是数字时,可以将原始值的数制基数转为一个不同的数字。例如,可以将十进制的原始值转为十六进制的哈希值。为了使哈希值的长度相同,可以省略高位数字。
6)数据重排法:这种方法只是简单的将原始值中的数据打乱排序。比如可以将第三位到第六位的数字逆序排列,然后利用重排后的数字作为哈希值。
4.冲突处理模式
装填因子:一个良好的散列函数将字典中的n个数据存储在容量为N的桶数组中,并期望每个桶的大小为n/N,则为散列表的装填因子。即数据个数与桶数组容量的比,通常装填因子小于1.
1)开放定址法
当冲突发生时,使用某种探查(亦称探测)技术在散列表中形成一个探查(测)序列。沿此序列逐个单元地查找,直到找到给定的关键字,或者碰到一个开放的地址(即该地址单元为空)为止(若要插入,在探查到开放的地址,则可将待插入的新结点存人该地址单元)。查找时探查到开放的地址则表明表中无待查的关键字,即查找失败。
注意:
①用开放定址法建立散列表时,建表前须将表中所有单元(更严格地说,是指单元中存储的关键字)置空。
②空单元的表示与具体的应用相关
Hi=(H(key)+di) MOD m, i=1,2,3,……k(k<=m-1);
H(key)为哈希函数;m为哈希表的长度;di为增量序列;增量序列有3种取法:
第一种:线性探测再散列 di=1,2,3,4……m-1;
使用线性探测散列会产生聚焦或堆积(散列地址不同的结点争夺同一个后继散列地址的现像叫聚焦或堆积)为了减少堆积的发生,不能像线性探查法那样探查一