散列及其实现

        散列是一种数据结构,可以对应python中的字典。基于散列的搜索算法的时间复杂度为 O ( 1 ) O(1) O1
        散列的实现是基于散列表和散列函数的。
        散列表是一种数据集合,散列表中的数据以特定的方式进行存储,以方便以后的查找。(这里面的特定的方式说的就是散列函数)散列表的每一个位置被称作一个“槽”,每个槽的编号以从零开始的整数命名。初始条件下,每个槽都是空的。可以使用python的列表来实现散列表,初始值为None. 图1展示了一个长度为11的散列表。


图1:有11个空槽的散列表

        散列函数是将数据项与储存数据项的槽的指引联系起来的一个映射函数。通过散列函数,可以将任意一个数据项存储到集合中,并返回一个介于槽区间命名之间的整数。一个简单的散列函数为求余函数,返回的余数为数据项的散列值(h(item)=item%11)。图二展示了一些数据项的散列值。


图2:数据项与其对应的散列值
在构建的散列函数的过程中,可能会出现不同数据项的散列值相同的情况,比如44%11=0,77%11=0。这种情况叫做冲突。没有冲突的散列函数可以被称为**完美散列函数**。但是很多时候要求散列函数为完美散列函数所付出的代价是极大的,比如很多的槽没有被数据项填充。我们需要的是冲突数量级比较低的散列函数。

         作为求余的拓展,这里介绍几种常见的散列函数。第一种是折叠法。比如一串电话号码43,64,55,46,01。我们将这一串号码分成五段,然后将每一段相加,对和求余得到散列值;第二种是平方取中。首先将数据项平方,平方之后,取所得数的中间两位,对哈希表的长度取余得到哈希值。对于字符串类型,通常我们是将字符转换成ASCII码来操作,比如"cat" 转换成99*1+97*2+116*3。 然后再对转换后的数据进行取余操作。

        由于实现完美散列函数需要的代价太大。所以我们一般散列函数都会有冲突,常见的冲突解决办法有线性探测。
        线性探测是通过算出数据项求余之后的散列值,如果有该散列值的槽被其他数据项占据则向后寻找剩下的槽直到找到一个空槽。(rehash(oldvalue)=(oldvalue+1)%sizeoftable)。这种线性探测的缺点是rehash的散列值可能会与某些数据项的第一次hash的hash值(散列值)冲突,而且第一次hash值相同的数据项会集中到一起。

解决集中的方法是拓展线性探测,即向后间隔寻找。此时的rehash函数变成(rehash(oldvalue)=(oldvalue+skip)%sizeoftable)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值