前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Hash表(三)——Hash函数&装载因子&动态扩容

Hash表(三)——Hash函数&装载因子&动态扩容

作者头像
用户3470542
发布2019-08-27 09:55:32
6.1K0
发布2019-08-27 09:55:32
举报
文章被收录于专栏:算法半岛算法半岛

Hash函数的确定

通过前面学习到, Hash表的查询效率并不是 O(1),它与 Hash函数、散列冲突等因素有关。如果 Hash函数确定得不好,可能导致散列冲突概率升高,查询效率下降。那么,该如何设计 Hash函数呢?

首先, Hash函数一般设计得不要过于复杂,过于复杂的 Hash函数会导致计算时间过多,从而影响散列表的性能;

其次, Hash函数生成的值要尽可能随机并且均匀分布,这样才能避免或者最小化散列冲突,而且即使出现冲突,散列到每个槽中的数据也会比较平均,不会导致某些槽中的数据过多,而另一部分槽中的数据过少的情况。

传统的 Hash函数的设计方法有直接寻址法、平方取中法、折叠法、随机数法等,也可以根据实际情况自己设计 Hash函数。

装载因子的确定

为了定量的表示 Hash表中空位的多少,定义装载因子

Hash表的装载因子 = 填入表中的元素个数 / Hash表的长度

由公式可知,装载因子越大,说明 Hash表中的元素越多,空闲位置越少,散列冲突的概率越大,散列表的性能就会下降。

对于没有频繁插入和删除的静态数据结合来说,可以根据数据的特点和分布情况设计出符合这些数据的 Hash函数,从而减少了散列冲突。

但是大部分情况下是动态数据,数据集合是频繁变动的,我们无法事先知道数据的个数,因此也无法事先申请一个足够大的 Hash表。随着数据加入,填入表中的元素个数增多,装载因子增大,当装载因子达到一定程度时,散列冲突便不可接受,因此我们无法根据数据的特征和分布情况设计出符合这些数据的 Hash函数,而是需要动态扩容,重新申请一个更大的 Hash表,将数据重新存储到新的 Hash表中。

如下图中的散列表,当装载因子达到0.8时进行扩容,装载因子变为0.4,原来的数据就会存储在新的 Hash表中。

当数据插入到 Hash表时,如果装载因子还未达到临界值,此时还不需要扩容,插入的数据非常快,但如果装载因子达到了临界值,这是就需要先进行扩容,然后再插入数据,这个时候就会变得很慢。

当数据需要从 Hash表中删除时,如果 Hash表已经经历过扩容,随着数据的删除,空闲空间会越来越多。当程序对内存空间非常敏感时,可以设置当装载因子小于某个临界值时,启动动态缩容,让内容空间得到充分利用;当程序对内存空间不太敏感时,就不需要进行动态缩容处理。

动态扩容策略

为了减少动态扩容耗时,我们可以将扩容的操作穿插在插入操作过程中。具体如下图所示:

这样每次插入时迁移一个数据,没有集中一次性迁移数据那样耗时,不会形成明显的阻塞。

由于迁移过程中,有新旧两个 Hash表,查找数据时,先在新的 Hash表中进行查找,如果没有,再去旧的 Hash表中进行查找。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 算法半岛 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 装载因子的确定
  • 动态扩容策略
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档