HashMap 底层数据结构和扩容机制面试连珠炮

HashMap 底层数据结构说一下?

HashMap底层数据结构为数组+红黑树,使用数组的原因是数组支持随机访问,可以实现O(1)的时间复杂度查询,在存储键值对时,会把键通过哈希函数映射到数组的下标索引,但是,哈希函数可能产生哈希冲突,即两个不同的键值对映射到同一个数组下标索引,HashMap底层采用链地址法来解决哈希冲突,但是链地址法有一个缺点,就是当发生哈希冲突的数据越来越多,一条链上的数据越来越长,而链表的查询效率时O(n)的时间复杂度,这样会降低查询效率,为了避免链表过长而降低查询效率,HashMap底层采用了红黑树的数据结构,但链表的长度超过8且数组的大小超过64时,就会把该链表转为红黑树,而红黑树的查询效率为O(logn)

为什么用红黑树呢?用平衡二叉树不可以吗?

平衡二叉树,又叫AVL树,虽然查询效率也很快,但是AVL树要遵循十分严格的平衡条件,即左右子树的高度差不超过1,为了达到这样的平衡条件,在添加或者删除树的节点是,需要经过多次左旋或右旋操作才能复衡。而红黑树没有严格遵守这样的平衡条件。

解决哈希冲突的方法?

  1. 链地址法:将每一个索引位置当作一条链表,发生哈希冲突的键值对会被放在同一个索引位置的链表上,查询的时候先通过哈希函数映射到数组索引下标,然后在链表上查询。
  2. 开放地址法:存储一个键值对时,如果发生了哈希冲突,会基于冲突的这个索引位置往后面遍历,如果没有元素,就把当前按的键值对放在这个索引位置,查询时,首先把键经过哈希函数映射到数组下标索引,然后比较该位置的key是否与当前要查询的key相等,如果相等就查询到,如果不相等,就往后遍历查询。

简单描述下 put 的流程?

HashMap map = new HashMap<>();
map.put("1",1);

以这句代码为例,调用put方法,put方法的源码如下:

public V put(K key, V value) {
	return putVal(hash(key), key, value, false, true);
 }

底层实际调用的是putVal方法,该方法的声明如下:

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict)

putVal的形参和实参如下:

形参实参
hashhash(key)
keykey
valuevalue
onlyIfAbsentfalse
evicttrue

hash函数是一个计算key哈希值的函数,参数是key,返回int类型的hash值,其源码如下:

static final int hash(Object key) {
    int h;
	return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

key 如果为null,哈希值就为0,这里说明HashMap是可以接受key为null,从而说明HashSet也可以接收key为null,因为HashSet就是HashMap去掉value那一半。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值