hashmap负载因子

hashmap负载因子,为什么设置成0.75

hashmap,底层实现是哈希表(数组+链表/红黑树)。哈希冲突时,hashmap采用链地址法解决hash冲突;为了防止退化带O(n)复杂度,hashmap规定链表长度超过8时,将链表转换成红黑树结构,图源网络。

1. 什么是hashmap负载因子?

hashmap负载因子(load factor),也叫扩容因子或者装载因子,它是hashmap中定义的一个阈值。当hashmap中的元素个数超过了哈希表容量x负载因子,哈希表会进行扩容,hashmap默认负载因子设置为0.75。举个栗子,hashmap默认创建的哈希表容量为16(懒加载机制,只有第一次put的时候才会实际创建具体空间),默认负载因子为0.75,当hashmap实际元素个数达到 16 x 0.75 = 12 时,hashmap会执行扩容操作。我们也可以通过构造函数来指定我们定义hashmap对象的负载因子。图源网络。

2. 为什么需要扩容?

当hashmap中的元素数量越来越多时,哈希冲突的概率会增大(因为数组的长度是固定的),所以需要对hashmap进行扩容操作,以提高元素查询的效率

3. 负载因子为什么设置成0.75?

先来看一下官方的答案:

As a general rule, the default load factor (.75) offers a good tradeoff between time and space costs. Higher values decrease the space overhead but increase the lookup cost (reflected in most of the operations of the HashMap class, including get and put). The expected number of entries in the map and its load factor should be taken into account when setting its initial capacity, so as to minimize the number of rehash operations. If the initial capacity is greater than the maximum number of entries divided by the load factor, no rehash operations will ever occur.

简单来说,默认负载因子为0.75时,时间和空间复杂度达到良好的平衡,空间利用率较高,同时避免了相当多的哈希冲突,使得底层的链表或者红黑树高度较低,有效提高空间使用效率。<至于原因,哈希冲突符合泊松分布,大佬从概率统计方面证明负载因子为什么选择7.5,What is the significance of load factor in HashMap?>

如果负载因子过大或者过小会发生什么?

  • 负载因子过大

上面我们说过,hashmap数据一开始是保存在数组中的,当发生哈希冲突时,就使用链表或者红黑树对冲突数据进行链接。当负载因子过大时(以1.0为例),hashmap只有当元素个数等于哈希表容量才会进行扩容,这会出现问题。因为哈希冲突是无法避免的,如果负载因子过大,意味着可能会出现大量的哈希冲突,底层的链式结构会变得较为复杂,从而带来更大的时间复杂度。总的来说,如果负载因子过大,虽然空间利用率较高,但是查询时间效率过低。

  • 负载因子过小

负载因子过小时(以0.5为例),意味着,当数组中的元素达到哈希表容量的一半就会开始扩容,hashmap填充的元素减少,哈希冲突也会减少,那么底层的链表长度或者是红黑树的高度就会降低,查询效率就会增加。但是,此时空间利用率就会大大的降低,原本存储1M的数据,现在需要2M的空间来进行存储。而且频繁的对表进行扩容需要对原有元素进行迁移,对机器负载增强。

总的来说,如果负载因子过小,虽然查询时间效率较高,但是空间利用率低,会造成不必要的空间浪费和频繁的元素迁移。

4. C++中的hashmap为什么默认设置负载因子为1.0?

C++ 语言中,std::unordered_map 默认的负载因子是 1.0,这意味着当 std::unordered_map 中的元素个数等于桶的数量时,就会触发扩容操作。

这个设计与 Java 中的 HashMap 等容器类有所不同。Java 中的 HashMap 默认负载因子是 0.75,而 C++ 的 std::unordered_map 默认负载因子是 1.0。主要的原因在于两种语言对哈希表的设计目标不同:

  • Java 的 HashMap 旨在提供一个高效、快速的哈希表实现,以便在大量数据场景下能够快速定位元素。通过对负载因子的优化,Java 的 HashMap 可以利用较少的空间和时间,同时保持良好的性能。

  • C++ 的 std::unordered_map 则更注重通用性和灵活性。虽然桶的数量和负载因子相关,但这些参数可以根据需要进行调整,以满足不同的需求。C++ 的 std::unordered_map 提供了多个构造函数,允许开发者在创建对象时指定桶的数量、负载因子和哈希函数等参数,以便根据实际情况进行适当的调整。

因此,将 C++ 的 std::unordered_map 的默认负载因子设为 1.0,一方面符合 C++ 对通用容器的设计理念,另一方面也使得 std::unordered_map 可以灵活应对不同的场景需求。当然,在实际使用中,我们也可以根据实际情况选择适当的负载因子,以获得更好的性能和空间利用率。

5. 参考

HashMap的负载因子为何默认是0.75

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值