面试官:为什么 HashMap 的加载因子是0.75?彻底懵逼了。。
阅读本文大概需要 7 分钟。
来自:blog.csdn.net/NYfor2017/article/details/105454097
-
为什么HashMap需要加载因子? -
解决冲突有什么方法? -
1.开放定址法 -
2.再哈希法 -
3.建立一个公共溢出区 -
4.链地址法(拉链法) -
为什么HashMap加载因子一定是0.75?而不是0.8,0.6? -
那么为什么不可以是0.8或者0.6呢?
-
为什么HashMap需要加载因子? -
解决冲突有什么方法? -
为什么加载因子一定是0.75?而不是0.8,0.6?
为什么HashMap需要加载因子?
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
// AbstractMap
public int hashCode() {
int h = 0;
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext())
h += i.next().hashCode();
return h;
}
加载因子 = 填入表中的元素个数 / 散列表的长度
-
散列函数是否可以将哈希表中的数据均匀地散列? -
怎么处理冲突? -
哈希表的加载因子怎么选择?
解决冲突有什么方法?
1. 开放定址法
Hi = (H(key) + di) MOD m,其中i=1,2,…,k(k<=m-1)
1.1 线性探查法(Linear Probing):di = 1,2,3,…,m-1
1.2 平方探测法(Quadratic Probing):di = ±12, ±22,±32,…,±k2(k≤m/2)
1.3 伪随机探测法:di = 伪随机数序列
-
这种方法建立起来的哈希表,当冲突多的时候数据容易堆集在一起,这时候对查找不友好; -
删除结点的时候不能简单将结点的空间置空,否则将截断在它填入散列表之后的同义词结点查找路径。因此如果要删除结点,只能在被删结点上添加删除标记,而不能真正删除结点; -
如果哈希表的空间已经满了,还需要建立一个溢出表,来存入多出来的元素。
2. 再哈希法
Hi = RHi(key), 其中i=1,2,…,k
3. 建立一个公共溢出区
4. 链地址法(拉链法)
-
处理冲突的方式简单,且无堆集现象,非同义词绝不会发生冲突,因此平均查找长度较短; -
由于拉链法中各链表上的结点空间是动态申请的,所以它更适合造表前无法确定表长的情况; -
删除结点操作易于实现,只要简单地删除链表上的相应的结点即可。
为什么HashMap加载因子一定是0.75?而不是0.8,0.6?
临界值 = DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR
* Ideally, under random hashCodes, the frequency of
* nodes in bins follows a Poisson distribution
* (http://en.wikipedia.org/wiki/Poisson_distribution) with a
* parameter of about 0.5 on average for the default resizing
* threshold of 0.75, although with a large variance because of
* resizing granularity. Ignoring variance, the expected
* occurrences of list size k are (exp(-0.5) * pow(0.5, k) /
* factorial(k)). The first values are:
* 0: 0.60653066
* 1: 0.30326533
* 2: 0.07581633
* 3: 0.01263606
* 4: 0.00157952
* 5: 0.00015795
* 6: 0.00001316
* 7: 0.00000094
* 8: 0.00000006
* more: less than 1 in ten million
0: 0.60653066
1: 0.30326533
2: 0.07581633
3: 0.01263606
4: 0.00157952
5: 0.00015795
6: 0.00001316
7: 0.00000094
8: 0.00000006
那么为什么不可以是0.8或者0.6呢?
对于开放定址法,加载因子是特别重要因素,应严格限制在0.7-0.8以下。超过0.8,查表时的CPU缓存不命中(cache missing)按照指数曲线上升。因此,一些采用开放定址法的hash库,如Java的系统库限制了加载因子为0.75,超过此值将resize散列表。
推荐阅读:
SpringBoot 运行内存及内存参数设置:助力高效应用部署与优化
互联网初中高级大厂面试题(9个G) 内容包含Java基础、JavaWeb、MySQL性能优化、JVM、锁、百万并发、消息队列、高性能缓存、反射、Spring全家桶原理、微服务、Zookeeper......等技术栈!
⬇戳阅读原文领取! 朕已阅