搜索之散列表

  • 散列表基础

散列表将数据映射到数据结构(数组、链表等)的相关位置,利用键与值之间的关系来达到快速搜索的目的,由于散列表将键与值联系起来,有时也称散列表为关联数组。

散列表映射键值得过程叫做散列(hashing)。键与值之间的函数关系,被称为散列函数,散列地址address = F(key),一个简单的散列函数为address = key Mod lengthOfHashTable。良好的散列函数往往会将相似的元素散列到不同的位置。

当把足够多的的值存放到散列表中,总会出现键相同的情况,这就是所谓的冲突,这时我们需要一个解决冲突的方法来决定怎么处理冲突。

散列表必须能添加元素及搜索元素,至于删除元素虽然有用,但有些散列表并不提供删除方法。

正如上面所说,一个散列表至少包含三部分,存储数据的数据结构、将数值映射到数据结构中的散列函数、处理冲突的方法

 

  •  链式散列表(分离链接法处理冲突,实际就是将散列表设计成链式的)

链式散列表即使用链表这种数据结构来构建散列表,这与稀疏数组十分类似,也可将之理解为“桶”或者邻接表的形式。

优点:对于链式散列表,由于使用的是链表这种灵活的数据结构,因此它不会出现散列表满或者散列冲突的情况;容易调整散列表大小(桶的数量);能直接删除桶中元素,而不影响整个散列表的索引。

缺点:当数据量庞大时(N),由于桶的数量(M)不够,会导致单个桶变得“很深”,即数据很多,这时虽然找到元素所在桶的地址不难O(1),但想要找到搜索目标就得在桶中搜索O(N/M)的时间。

  • 开放地址法

开放地址法是除链式散列表外另一种散列表的创建方式。开放地址法使用数组来创建散列表,因此这种散列表调整大小比较花费时间,一般是通过把原散列表复制到新散列表的形式来调整大小。

优点:相比于链式散列表,省去了搜索桶的时间,在填充度合理的情况下,搜索速度是非常快的

缺点:容易出现冲突;不能直接删除元素,只能采取标记的方式来删除元素。

搜索数据:

*** 若散列地址数据就是搜索目标,即工作完成。

*** 若在探测过程中发现空位置,则说明,目标不在散列表中。

*** 若散列表访问了N个元素(散列表长为N),则说明目标不在散列表中,因为此时程序已经进入到了一个序列的循环之中,需退出搜索,原因是若目标在散列表中,则在探测第N个位置只前,必定能找到目标。

解决冲突的方法

探测序列:当插入新值时,由散列函数获得的插入位置已存在数据,此时即为散列冲突,此时我们需要给这个新值重新选择一个散列地址,简单的我们可以选择后面一个地址作为新的散列地址,此时若再次冲突,则需再次探测下下一个地址,这时的探测序列即为[0,1,2,3,4,...],其他的探测序列还有[0,1^2,2^2,3^2,4^2,....]等

*** 线性探测

线性探测是探测序列为[0,1,2,3,4....]的探测方法。

线性探测往往具有主簇的缺点,即往往会形成段很长的完全被填满的序列,为什么会这样呢?原因是,比如一个元素插入在长为N的数组的K位置的概率为1/N,那么接下来在一个元素插入在K+1位置的概率为2/N(K位置冲突,探测下一个位置K+1),如此一来,慢慢的一片长的序列就形成了。

主簇会影响散列表的搜索速度,由于大片长的序列的存在,当搜索一个元素时,可能要进行多次探测,当目标不存在时,甚至要探测N次。

*** 二次探测(平方探测)

二次探测是探测序列为[0,1^2,2^2,3^2,4^2,....]的探测方法。

类似于线性探测,二次探测具有二次簇的缺点,同时可能有很多空位置,也不被用到,即即使散列表没有满,也无法插入这个特定新元素

*** 伪随机探测

采用伪随机探测序列,伪随机之所以伪是因为它是人造的,对于伪随机数构造器,给定参数,输出的伪随机数组是一定的,因此,当冲突发生时,探测序列是不变的,即也会同线性探测、二次探测一样会产生簇,同样也会有很多空位置不被用到。

*** 双散列

在伪随机探测基础之上,进行了改进:对于不同的值发生冲突时,使用不同的参数来生成不同的伪随机序列。但还是会有很多空位置不被用到。

提高搜索速度:

有序序列的搜索速度肯定是要快于无序序列的,因此我们可以构建有序的链式散列表来提升索引速度

构建有序散列表的方法

当在插入元素时,若桶中元素为空,则直接插入,

否则比较元素值,若大于新元素,则将新元素插入在这个位置,然后转而重新散列这个大的元素,这可以用递归实现,

若小于新元素,则继续探测下一个地址。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值