开放定址法
开放寻址法的核心思想是,如果出现了散列冲突,我们就重新探测一一个空闲位置,将其插入。比如,我们可以使用线性探测法。当我们往散列表中插入数据时,如果某个数据经过散列函数散列之后,存储位置已经被占用了,我们就从当前位置开始,依次往后查找,看是否有空闲位置,如果遍历到尾部都没有找到空闲的位置,那么我们就再从表头开始找,直到找到为止
①. 线性探测 按顺序决定哈希值时,如果某数据的哈希值已经存在,则在原来哈希值的基础上往后加一个单位,直至不发生哈希冲突。
②. 再平方探测 按顺序决定哈希值时,如果某数据的哈希值已经存在,则在原来哈希值的基础上先加1的平方个单位,若仍然存在则减1的平方个单位。随之是2的平方,3的平方等等。直至不发生哈希冲突。
③. 伪随机探测 按顺序决定哈希值时,如果某数据已经存在,通过随机函数随机生成一个数,在原来哈希值的基础上加上随机数,直至不发生哈希冲突。
链式地址法(HashMap的哈希冲突解决方法)
对于相同的哈希值,使用链表进行连接。使用数组存储每一个链表。将哈希表的每个单元作为链表的头结点,所有哈希地址为 i 的元素构成一个同义词链表。即发生冲突时就把该关键字链在以该单元为头结点的链表的尾部。
双散列(Double Hashing)
-
使用两个哈希函数,第一个哈希函数确定插入位置,第二个哈希函数用于计算步长(在发生冲突时决定下一个尝试的位置)。
-
这可以减少聚集效应,提高哈希表的性能。
再哈希(Rehashing)
-
当哈希表达到一定的负载因子时(已存储元素数量与哈希表大小的比率),可以选择进行再哈希。
-
再哈希是指创建一个更大的哈希表,然后将现有元素重新插入到新表中,以减少冲突的可能性。
建立公共溢出区
这种方法的基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。
拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短; 由于拉链法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况; 开放定址法为减少冲突,要求装填因子α较小,故当结点规模较大时会浪费很多空间。而拉链法中可取α≥1,且结点较大时, 拉链法中增加的指针域可忽略不计,因此节省空间; 在用拉链法构造的散列表中,删除结点的操作易于实现。只要简单地删去链表上相应的结点即可。而对开放地址法构造的散列表, 删除结点不能简单地将被删结点的空间置为空,否则将截断在它之后填人散列表的同义词结点的查找路径。