HashMap

一、HashMap结构及原理 

HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

 HashMap 实际上是一个“链表散列”的数据结构,即数组和链表的结合体。

新建一个HashMap的时候,就会初始化一个数组,默认大小为16。Node就是数组中的元素,每个Node其实就是一个key-value的键值对,它持有一个指向下一个元素的引用,这就构成了链表,HashMap底层将key-value当成一个整体来处理,这个整体就是一个Node对象。

HashMap底层采用一个Node[ ]数组来保存所有的key-value键值对,当需要存储一个Node对象时,会根据hash算法来决定在其数组中的位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Node对象时,也会根据hash算法找到其在数组中的存储位置, 在根据equals方法从该位置上的链表中取出Node;

 

二、常用方法

1. get()

通过计算hash值获取元素,平均查询效率为O(1) 。

public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
}

2. put()

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

3. remove()

从该映射中移除指定键的映射(如果存在)。

三、常见问题

1. HashMap扩容机制

  扩容必须满足两个条件

  • 存放新值的时候当前已有元素必须大于阈值;
  • 存放新值的时候当前存放数据发生hash碰撞(当前key计算的hash值计算出的数组索引位置已经存在值)

每次扩容扩大一倍,即size=size*2;

HashMap在添加值的时候,它默认能存储16个键值对,直到你使用这个HashMap时,它才会给HashMap分配16个键值对的存储空间,(负载因子为0.75,阈值为12),当16个键值对已经存储满了,我们在添加第17个键值对的时候才会发生扩容现象,因为前16个值,每个值在底层数组中分别占据一个位置,并没有发生hash碰撞。
HashMap也有可能存储更多的键值对,最多可以存储26个键值对,我们来算一下:存储的前11个值全部发生hash碰撞,存到数组的同一个位置中,(这时元素个数小于阈值12,不会扩容),之后存入15个值全部分散到数组剩下的15个位置中,(这时元素个数大于等于阈值,但是每次存入元素并没有发生hash碰撞,不会扩容),11+15=26,当我们存入第27个值得时候满足以上两个条件,HashMap才会发生扩容;

2.Hash冲突的解决方法

1) 开放定址法

当冲突发生时,使用某种探查(亦称探测)技术在散列表中形成一个探查(测)序列。沿此序列逐个单元地查找,直到找到给定的关键字,或者碰到一个开放的地址(即该地址单元为空)为止(若要插入,在探查到开放的地址,则可将待插入的新结点存人该地址单元)。查找时探查到开放的 地址则表明表中无待查的关键字,即查找失败。

2) 再哈希法

对于冲突的哈希值再次进行哈希处理,直至没有哈希冲突。

3) 链地址法

对于相同的值,使用链表进行连接。使用数组存储每一个链表。

4) 建立公共溢出区

建立一个公共溢出区域,就是把冲突的都放在另一个地方,不在表里面。

3. HashMap查找时间复杂度

1) 理想情况下,哈希不冲突,可以直接找到结果,所以O(1)

2) 在最差的情况下,HashMap保存的数据都在链表中保存,所以需要遍历链表,所以时间复杂度为O(n)。

4. 桶的树形化(红黑树)

如果一个桶中的元素个数超过 TREEIFY_THRESHOLD(默认是 8 ),就使用红黑树来替换链表,从而提高速度。这个替换的方法叫 treeifyBin() 即树形化。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值