有两种策略来解决hash table的碰撞问题。第一种策略是open addressing,如果数组中当前位置已经被占用,他会为当前数据重新选择一个位置;第二种策略是separate chaining,在数组每一个位置安放一个链表。
1.Open Addressing
如果当前数据所修位置被占用,该策略会为数据重新选择一个位置。这种测略有三种方法可以使用:
a.Liner probing
这种方法简单的以当前位置为起点,线性搜索空闲位置。如果hash函数选择了第n个位置给当前数据,但是n位置已经被占用,该方法将会尝试n+1,n+2.........,知道找到一个空闲位置,如果到达数组末尾,则从数组头继续搜索。这个尝试不同位置的过程叫做probing。
之所以叫做Liner probing,是因为这个过程看起来像线性搜索。
当需要在hash table中搜索数据时候,同样要是用probing,当通过key来搜索数据,且hash函数得到的位置是x,如果x位置包含其他的数据,那么继续搜索x+1,x+2,直到搜索到目标元素,或者x+k位置为空,或者又重新便利到x位置。
Liner probing的问题是clustering(聚合),数据元素成块状分布。如果插入一个映射到x位置的值,但是x被占用了,插入方法将尝试x+1。如果下一个元素被映射到x+1,而这个位置被占用了,那他就得继续往后尝试。数据将会聚集成一块一块的。在实际应用中,如果插入数据相似,那么会产生数据聚合,导致搜索和插入数据效率下降。
解决这个问题的方法是move ahead,不仅仅是前移一个元素位置。在quadratic probing中,插入方法将尝试x+1^2,x+2^2,x+3^2.........直到找到空闲位置,在查找时候也要这么做。
b.Quadratic probing
Quadratic probing的好处是可以降低clustering,因为probing的偏移是n^2,而不是1,不会使得数据很接近。但是如果很多数据同时被映射到同一个位置上,那么这种方法也是于事无补的。当有很多数据被映射到同一个位置时候,他将会尝试x+1,x+4,x+9...............这将使数据查找变得困难。
c.double hashing
double hashing中,probing的偏移取决于key value自己。当key映射到位置x,而x已经被占用的时候,则用第二个hash函数对key进行处理得到y,尝试x+y,x+2y,x
+3y..........直到找到一个可以插入的位置。选择第二个hash函数的目标是:hash函数值永远大于等于1,对于key的得到的hash结果和第一个hash函数不同。通常,第二个hash函数这么写:
probe offset = c - key%c, c是一个小于数组大小的常数
2.Separate chaining
这种方法在数组的每一个位置上用一个链表