HashMap底层数据结构

jdk1.8之前:数组+链表

jdk1.8之后:数组+链表+红黑树

  1. 数组的时间复杂度:O(1)
  2. 链表的时间复杂度:O(N)
  3. 红黑树时间复杂度:O(logn)

为什么使用数组?

数组的的读、写速度快。(查询快,增删慢)

为什么使用链表?

为了避免数据的KEY产生哈希碰撞后将原有的数组下标对应的值直接替换。(查询慢,增删快)

为什么使用红黑树?

为了解决链表过长性能低的问题,增加查找,插入,删除的效率。

 

HashMap的put()和get()的实现:

map.put(k,v)实现原理

1.先将k、v封装到NODE对象当中;

2.底层调用k的hashcode()方法计算出hash值;

3.(return h & (length-1))h代表hash值,length代表HashMap的容量

通过取模算法计算出数组的下标,如果下标的位置上没有元素,就会把Node添加到这个位置上,

如果下标的位置上有链表,就会调用object中的equals方法将Node中k和链表中每个节点的k进行比较,相同会直接覆盖,不相同会添加到链表的末尾。

当单向链表数据结构长度大于8时,会形成红黑树数据结构,增加性能。当红黑树上的节点数量小于6个,会重新把红黑树变成单向链表数据结构。

map.get(k)实现原理

1.底层调用k的hashcode()方法计算出hash值;

2.通过hash值用取模算法计算出数组下标,快速定位到某个位置上,如果该位置上没有值,直接返回null,

如果该位置上由单向链表,就会调用object中的equals方法将Node中k和链表中每个节点的k进行比较,

如果equals方法返回false,则get结果为null,如果equals方法返回true,则get结果为该节点的value。

 

hashmap初始容量为什么是16?

基于效率和内存使用上的一个权衡值;

太大了浪费空间,太小了,频繁扩容,影响效率。

为什么加载因子为0.75f?

因为0.75正好是3/4,而容量又是2的幂,两个数的乘积始终为整数

为什么HashMap中链表长度超过8会转换成红黑树?

红黑树的平均查找长度是log(n),长度为8,查找长度为log(8)=3,链表的平均查找长度为n/2,当长度为8时,平均查找长度为8/2=4,这才有转换成树的必要;

链表长度如果是小于等于6,6/2=3,虽然速度也很快的,但是转化为树结构和生成树的时间并不会太短。

还有选择6和8的原因是:

  中间有个差值7可以防止链表和树之间频繁的转换。假设一下,如果设计成链表个数超过8则链表转换成树结构,链表个数小于8则树结构转换成链表,如果一个HashMap不停的插入、删除元素,链表个数在8左右徘徊,就会频繁的发生树转链表、链表转树,效率会很低。

posted @ 2021-02-19 17:10  喜之郎飞饼  阅读(173)  评论(0)    收藏  举报