哈希冲突详解
我喜欢用问答的形式来学习,这样可以明确许多不明朗的问题。
-
什么是哈希冲突?
比如我们要去买房子,本来已经看好的房子却被商家告知那间房子已经被其他客户买走了。这就是生活中实实在在的冲突问题。
同样的当数据插入到哈希表时,不同key值产生的h(key)却是相等的,这个时候就产生了冲突。这个时候就要解决这个问题。
-
怎么解决哈希冲突?
方法1:拉链法
方法2:开地址法 -
何为拉链法?
拉链法是解决哈希冲突的一种行之有效的方法,某些哈希地址可以被多个关键字值共享,这样可以针对每个哈希地址建立一个单链表。
在拉链(单链表)的哈希表中搜索一个记录是容易的,首先计算哈希地址,然后搜索该地址的单链表。
在插入时应保证表中不含有与该关键字值相同的记录,然后按在有序表中插入一个记录的方法进行。针对关键字值相同的情况,现行的处理方法是更新该关键字值中的内容。
删除关键字值为k的记录,应先在该关键字值的哈希地址处的单链表中找到该记录,然后删除之。
-
什么是开地址法?
首先该方法并不建立链表。哈希表由M个元素组成,其地址从0到M-1。我们通过从空表开始,逐个向表中插入新记录的方式建立散列表。
插入关键字值为key的新纪录的方法是:
从h(key)开始,按照某种规定的次序探查插入新记录的空位置。h(key)被称为基位置。如果h(key)已经被占用,那么需要用一种解决冲突的策略来确定如何探查下一个空位置,所以这种方法又称为空缺编址法。
根据不同的解决冲突的策略,可以产生不同的需要被检查的位置序列,称为 探查序列。
根据生成的探查序列的不同规则,可以有 线性探查法、伪随机探查法、二次探查法 和 双散列法等开址方法。 -
线性探查法详解
缺点:线性探查法在情况不好的时候导致许多记录在散列表中连成一片,从而使探查次数增加,影响搜索效率。这种现象称为基本聚集。
线性探查法是一种简单的开地址方法,它使用下列循环探查序列:
h(key),h(key)+1,...,M-1,0,...,h(key)-1
从基位h(key)开始探查该位置是否被占用,即是否为空位置。
如果被占用,则继续探查位置h(key)+1,若该位置也已占用,再根据探查序列中的规定继续检查下一个位置。
因此,探查序列为:h(i) = (h(x)+i) % M (i=0,1,2,...,M-1)
-
伪随机法详解
伪随机法是为了消除线性探查的基本聚集而提出来的方法。其基本思想是建立一个伪随机数发生器。当发生冲突时,就利用伪随机数发生器计算下一个探查位置。伪随机数发生器有不同的构造。
一个比较简单的伪随机数产生方法:
y(0) = h(key) y(i+1) = (y(i)+p) % M (i=0,1,2,...) 式中,y(0)为伪随机数发生器的初值,M为哈希表的长度, P为与M接近的素数。
-
二次探查法详解
二次探查法也能够消除基本聚集,虽然伪随机数法和二次探查法都能够消除基本聚集。但是如果两个关键字值有相同的基本位置,那么它们就会有相同的探查序列。这是因为伪随机数法和二次探查产生的探查序列是基位置的函数,而不是原来关键字的函数,因此由产生了二次聚集的问题。
- 双散列法详解
使用双散列方法可以避免二级聚集。双散列法使用两个散列函数,第一个散列函数计算探针序列的起始值,第二个散列函数计算下一个位置的探查步长。