首先讲一下,数据结构中常见的时间复杂度 及大小排序
Ο(1)<Ο(logn)<Ο(n)<Ο(nlogn)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!) //查询一个数据从简单到复杂
HashMap 1.7和HashMap 1.8的区别
1、hashMap的时间复杂度
jdk 1.8之前版本由于HashMap底层是通过 数组加链表 的方式实现的,要找到数组对应的下标,只需要进行一次取模运算,但是找到数组对应下标之后,如果entry链表太长的话,还是需要时间遍历比较。所以说entry链表越短越好,最好每个数组后面只跟一个链表,这样就能达到 O(1) 的时间复杂度,
如果最差的情况下,即所有元素的hashCode都一样,那就放在同一个bucket后面,这样时间复杂度就会达到 O(n),但这种情况概率几乎没有。
2、jdk1.7和1.8 hashMap线程不安全
多线程put的时候导致数据不一致。
比如:有两个线程A和B,A在向HashMap中put数据的时候,首先计算出数组的下标,然后获取该桶的链表表头节点,此时线程A的时间片用完了,而此时线程B得以调用,
线程B成功的插入了数据。假设线程A和线程B的hashCode值计算出来的桶索引是一样的,当线程B成功插入后,线程A再度调用执行,线程A持有过期的链表头而不知道,
导致线程A直接覆盖了之前线程B插入的数据,造成数据不一致的结果。
实现一个安全的Map 其实就是synchronizedMap
Map<String, String> synchronizedHashMap = Collections.synchronizedMap(new HashMap<String, String>());
3、hash值算法有变化
JDK 1.7 采用4次位运算+5次异或运算
JDK 1.8采用1次位运算+1次异或运算
4、数据结构不同
1.7的为数组+链表, 1.8的存储结构为数组+链表+红黑树。
引入红黑树原因:
提高HashMap性能,解决了由于哈希碰撞链表过长导致索引效率慢的问题。利用红黑树增删改查的特点,时间复杂度从O(n)降低为O(logn)
重点:当链表长度大于等于8,自动将链表转化为红黑树,当链表长度小于8,将红黑树转化成链表,jdk1.7 链表节点是是entity ,jdk1.8是Node。
1.8中HashMap中的数组元素 & 链表节点 采用 Node类 实现,HashMap中的红黑树节点 采用 TreeNode 类 实现
添加红黑树之后,添加的核心参数。
(1).桶的树化阈值
即链表转成红黑树的阈值,在存储数据时,当链表长度大于该值时,则将链表转换成红黑树。
(2).桶的链表还原阈值
-即红黑树转换为链表的阈值。
-当在扩容之后,HashMap的存储位置会重新计算,此时如果原有的红黑树内数量 小于 阈值时,将红黑树转换为链表
(3). 最小树形化容量阈值
-当哈希表中的容量 > 该值时,才允许树形化链表。
-否则,若桶内元素过多,则直接扩容,而不是树形化。
-为了避免扩容和树形化的冲突,这个值不能小于 4 * 桶的树形化阈值
4、插入数据方式变化
JDK1.8采用尾插法,JDK1.7采用的是头插法
5
博文推荐:https://blog.csdn.net/LuQiaoYa/article/details/88786769