java基础学习004——哈希表性能优化原理

哈希表的扩容和链表优化为二叉树(如红黑树)是两种不同的性能优化策略,分别针对哈希冲突和查询效率问题。以下是它们的触发条件和原理:

1.哈希表数组的扩容
触发条件:

哈希表的底层数组通常在以下情况下触发扩容:
1、负载因子(Load Factor)超过阈值:

负载因子 = 当前元素数量 / 数组容量。  
 默认阈值通常为0.75。当负载因子超过该值时,哈希冲突概率显著增加,查询效率从平均 O(1) 退化为 O(n)(链表情况下),所以此时需要扩容。

插入新元素时发现容量不足:  在插入前检查负载因子,若超过阈值,则先扩容再插入。

扩容过程:

  1. 新建一个更大的数组(通常是原容量的2倍,如从16扩容到32)。
  2. 重新计算所有键的哈希值并分配到新数组中。
  3.  扩容代价较高,但能显著减少后续冲突。

2. 链表优化为二叉树
触发条件:

在哈希表的同一个桶(Bucket)中,当链表长度过长时,会将其转换为红黑树。

主要触发条件有两个因素,链表长度以及数组容量:

  1. 当链表长度超过阈值时:  Java中默认阈值为8(即链表长度超过8时转换为红黑树)。
  2. 数组容量达到最小树化容量:   Java中要求数组长度至少为 64。如果未达到,即使链表长度超过8,也会优先扩容数组而非树化。

优化目的:


最坏情况下,链表查询时间复杂度为O(n),而红黑树为O(log n)。当哈希冲突严重时,树化能避免极端情况下的性能退化。
反向操作:当红黑树节点数少于阈值(Java中为6),会退化为链表。而树化的阈值和退化的阈值之间有差值,目的就是避免频繁的树化和退化转换,导致性能下降。而在节点数目不是那么多的情况下,退化为链表反而能够减少内存浪费,同时这时候链表查询和红黑树查询实际差距很小。

总结:通过扩容和树化,哈希表能在高负载和哈希冲突严重时仍保持较高的性能。这两种策略共同保证了哈希表在时间和空间效率上的平衡。

哈希函数的设计思路

java中哈希函数的设计逻辑

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
int index = (n - 1) & hash;
  • h>>>16:将哈希值无符号右移 16 位,相当于取高 16 位。
  • h^(h>>>16):原始哈希码与高位异或,混合高低位,使高位的信息参与低位计算。
  • 映射桶下标的过程中通常会用到 hash&(n-1) 作为索引。

如果 hashCode() 获得的值本身的低位变化不够,直接使用低位会导致哈希冲突较多。因此,Java 通过高低位混合来提升哈希分布的均匀性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值