HashMap底层数据结构
jdk1.8之前:数组+链表
jdk1.8之后:数组+链表+红黑树
- 数组的时间复杂度:O(1)
- 链表的时间复杂度:O(N)
- 红黑树时间复杂度: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左右徘徊,就会频繁的发生树转链表、链表转树,效率会很低。

浙公网安备 33010602011771号