HashMap 的底层数据结构是什么?
在JDK1.7和JDK1.8中有所区别:
JDK1.7:由“数组+链表”组成,数组是HashMap的主体,链表则是主要为了解决Hash冲突而存在的。
JDK1.8:由“数组+链表+红黑树组成”,当链表过长则会严重影响HashMap的性能,红黑树搜索时间复杂度为O(logn),而链表是O(n)。因此JDK1.8对数据结构做了进一步的优化,引入了红黑树,链表和红黑树在达到一定的条件时会进行转换:
- 当链表长度超过阈值8且数组长度超过64才会转为红黑树
- 将链表转换为红黑树前会判断,如果当前数组的长度小于阈值64,那么会选择先进行数组扩容,而不是转为红黑树,以减少搜索时间。
说一下HashMap的特点?
- HashMap的存取是无序的
- 键值位置都可以是null,但是键位置只能是一个null
- 键是唯一的,底层的数据结构是控制键的
- JDK1.8后阈值>8并且数组长度大于64,才将链表转为红黑树,目的是提高搜索速度,实现高效查询
解决Hash冲突的办法有哪些?HashMap用的哪种?
解决Hash冲突的fangfayou:开放地址法,再哈希法,链地址法(hashmap中常见的拉链法),建立公共溢出区。
- 开放定址法也称为再散列法,基本思想就是,如果p=H(key)出现冲突时,则以p为基础,再次hash,p1=H§,如果p1再次出现冲突,则以p1为基础,以此类推,直到找到一个不冲突的哈希地址pi。因此开放定址法所需要的hash表的长度要大于等于所需要存放的元素,而且因为存在再次hash,所以只能在删除的节点上做标记,而不能真正删除节点
- 再哈希法(双重散列,多重散列),提供多个不同的hash函数,R1=H1(key1)发生冲突时,再计算R2=H2(key1),直到没有冲突为止。这样做虽然不易产生堆集,但增加了计算的时间。
- 链地址法(拉链法),将哈希值相同的元素构成一个同义词的单链表,并将单链表的头指针存放在哈希表的第i个单元中,查找、插入和删除主要在同义词链表中进行,链表法适用于经常进行插入和删除的情况。
- 建立公共溢出区,将哈希表分为公共表和溢出表,当溢出发生时,将所有溢出数据统一放到溢出区
注意开放定址法和再哈希法的区别是
- 开放定址法只能使用同一种hash函数进行再次hash,再哈希法可以调用多种不同的hash函数进行再次hash
停更。。。。