散列

一:散列函数

散列是一种用于以常数平均时间执行插入,删除和查找的技术。每个关键字被映射到从0到tablesize-1这个范围中的某个数,并且被放到适当的单元中,这个映射就叫做散列函数。
  通常,我们可以以一个素数来作为表的大小。
  散列冲突是说两个关键字散列到同一个值。

二:冲突解决

冲突解决的办法有两种:分离链接法和开放定址法。
1.分离链接法
  其做法是将散列到同一个值的所有元素保留到同一个表中。就是将有冲突的值放到一个链表中,散列表存储一个链表数组。
  在该方法中,平均查找时间与“装填因子”有关,装填因子是指散列表中的元素的个数对该表的大小的比。分离链接散列法的一般法则是使得表的大小与预料的元素个数大致相等。换句话说,就是让装填因子的值为1。
2.不用链表的散列表
  开放地址的意思是说,当冲突发生时,该冲突的元素会以某种策略被放置到一个空闲的地址,这个地址就是开放的。
  由于链表解决冲突的办法不仅在新单元分配地址上需要花费时间导致算法速度慢之外还要求对第二种数据结构链表进行实现。因此另外一种不用链表解决冲突的方法是尝试另一些单元,直到找到空的单元为止。所以这种解决方式所需要的表要比分离链接散列的表大。一般来说,对于不使用分离链接的散列表来说,其装填因子应该低于0.5,我们把这样的表叫做探测散列表。这种方法包括三种方法,分别是线性探测法平方探测法双散列
  (1) 线性探测法
   实质上,线性探测法就是顺延,当有冲突发生时,就按照一个线性函数(如f(i) = i,其中i表示冲突的次数)去计算找出下一个开放地址,将该冲突的元素放入到该开放地址,从而解决冲突。
   此方法中,占据的单元会形成一些区块,其结果称为一次聚集
  (2)平方探测法
   平方探测是为了消除线性探测中的一次聚集问题的冲突解决方法。平方探测就是冲突函数为二次的探测方法(比如f(i) = i^2,其中i表示冲突次数),该函数表示冲突元素应该放置在距离冲突位置为f(i)的地方,i为该元素为第几次发生冲突
   虽然平方探测排除了一次聚集,但是散列到同一位置上的那些元素将探测相同的备选单元,这叫做二次聚集
  (3)双散列
    这个解决冲突的办法是双散列,对于双散列,它会解决二次聚集,但是付出的代价是计算一个附加的散列函数。
    对于双散列,一种流行的做法是选择f(i) = i * hash_2(x),这个公式是说,我们将第二个散列函数应用到x并在距离hash_2(x),2hash_2(x),…等处探测。因此如果这个函数选择的不好,将是灾难性的。此外,这种双散列的方式中保证表的大小为素数非常重要。
3. 再散列
  再散列是说当散列表填的太满,消耗的运行时间太长会导致操作失败,可能发生太多的移动和插入混合的场合,因此,一种解决的方式就是建立另外一个大约两倍大的表(而且使用一个相关的新的散列函数),扫描整个原始散列表,计算每个(未删除的)元素的新散列值并将其插入到新表中
  当散列表太满(比如超过70%的单元被占用),这时就可以建立一个新的散列表和一个新的散列函数,扫描原来的表,重新进行散列,这个整个操作就叫做再散列。这是一种开销很大的散列表,其运行时间大约是O(n)。
4.完美散列
  完美散列是指按照最原始的思路,每个二级散列表将用一个不同的散列函数进行构造,直到没有冲突为止,如果产生的冲突多次高于要求的值,主散列表也可以被构建多次,这种方法称为完美散列。也就是说完美散列就是将冲突的元素再延伸成为一个散列表,也就是散列表存储的是散列数组(可类比链表数组)。
5.布谷鸟散列 
  布谷鸟散列说是有两个分别超过半空的散列表,且有两个散列函数,可以把每一个项分配到表中的有个位置。布谷鸟散列不变的是一个项总会被存储在这两个位置之一。两个超过半空的散列表的意思是说,在每一个散列表中包含两列,第一列为序列编号,第二列才是真正的要插入的项所在位置。散列函数给出了同一个项对应的可以存储在两个表中的哪个编号中。
  布谷鸟散列算法的策略是:当发生冲突时,当前项会面临两个选择,可以在第二个散列表中去存储到相应编号,但问题是第二个表对应编号位置可能已经被占,第二个选择就是直接挤掉第一个表中与当前项冲突的项,将原来被挤掉的项根据散列函数中在第二个散列表中的位置进行存储。而布谷鸟散列就是采用第二种方式,按照这样的方式一直循环替换,直到所有的项都放入合适位置。一般情况下是可以成功结束的,但是由于此过程中存在一个循环,也可能导致插入不成功。庆幸的是,有分析证明,循环的概率非常低,替换次数的期望值是一个小常数,并且每次插入成功替换的次数不会超过O(logN)次。当然,也可以用更多的散列表来实现,这样,布谷鸟散列表经常被实现成一张很大的表,带有相应个数的散列函数以及各种变形算法,只要有可用的地方就立刻尝试将一个项放入第二张散列表中。布谷鸟散列对于散列函数的选择极其敏感。 
6. 跳房子散列
  跳房子散列是尝试改进线性探测算法的一种新的算法。线性探测其实是很有用的,甚至是最有效的。跳房子散列的思路是:用事先确定的,对计算机底层体系结构而言是最优的一个常数,给探测序列的最大长度加个上界。如果某次插入要把一个新的项放到距离它的散列位置太远的地方,我们会有效的掉头向散列位置走,替换掉潜在的项。如果足够谨慎,那么替换可以很快完成,并且保证那些被替换的项都不会放在距离它们的散列位置太远的地方。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值