hashmap hash冲突怎么解决_极致 HashMap 番外(1)HashMap 常见问题

3ae09101bc4ececce015cde3264dc015.png

(1) HashMap 的实现原理

  • 你看过HashMap源码嘛?知道原理嘛?
1.7 版本是数组+链表,数组为了根据 hash 值定位索引,链表解决 hash 冲突
1.8 版本增加红黑树解决长链表查询问题
  • 为什么用数组+链表?
数组是为了快,链表是由于使用链地址法解决hash冲突
  • hash 冲突你还知道哪些解决办法?
开放地址法,再哈希法等
  • 我用 LinkedList 代替数组结构可以么?
可以,也能实现。但是过于愚蠢,因为链表的查询为O(N),性能和根据索引查询的数组没有可比性。
  • 既然是可以的,为什么HashMap不用LinkedList,而选用数组?
见上

(2) HashMap 扩容

  • HashMap 在什么条件下扩容?
table 容量达到负载上限,默认 75% 的总容量。
  • 为什么扩容是 2 的 n 次幂?
扩容翻倍是一个合理的状态,把长度定为2的幂,可以获得计算索引时的高性能
  • 为什么为什么要先高 16 位异或低 16 位再取模运算?
增加数据扰动,否则会出现数据连续存储的情况

(3) HashMap 的 get/put

  • 知道 HashMap 中 put 元素的过程是什么样么?
根据 key 算出索引 i,根据 i 查找数组。如果对应的那个位置上有数据,则判断是否相同。相同则覆盖。不相同则插入链表,尾插法。如果链表长度达到阈值,则转化为红黑树。
  • 知道 HashMap 中 get 元素的过程是什么样么?
大致于上相同,只不过换为查找。
  • 你还知道哪些 hash 算法?
MD4, MD5
  • 说说 String 中 hashcode 的实现?
以31为底,将每个字符转化成数字。选择31,有质数的考量,有32-1的好优化的考量

(4) HashMap 红黑树

  • 知道 jdk1.8 中 HashMap 改了啥么?
一是头插法变为尾插法,二是链表过长转为红黑树。
  • 为什么在解决 hash冲突的时候,不直接用红黑树?而选择先用链表,再转红黑树?
因为毕竟链表长度过长是一个不常见的现象,Java 自己做的统计得出只有百万分之六的情况下会产生过长。而红黑树是有成本的, 其自带的右旋左旋变色等操作在数量只有几个的情况下除了增加时间没有什么太大的意义。
  • 我不用红黑树,用二叉查找树可以么?
可以,但是不建议。红黑树来源于2-3树,2-3树来源于AVL,AVL来源于BST。
依次解决的问题是2-3树要处理多类节点,AVL树操作费时费力,BST在最坏情况下表现很差。而且红黑树已经成为了经典的解决这类问题的方法,再退回到原始状态当然也行,只不过毫无意义。
  • 那为什么阀值是8呢?
见上
  • 当链表转为红黑树后,什么时候退化为链表?
红黑树容量降到了反树化的阈值,默认是6。

(5) HashMap 并发

  • HashMap在并发编程环境下有什么问题啊?
一般性的错读错写,以及特殊情况下的程序死循环
  • 在jdk1.8中还有这些问题么?
一般性的错读错写还存在,特殊情况下的程序死循环被解除
  • 你一般怎么解决这些问题的?
ConrurrnetHashMap

(6) HashMap 的 key

String , Integer。一般来说,要选择Java帮你实现了hashcode的类,如果类还是不可变的就更好了。

抽象类和接口区别?

接口就是一种特殊的abstract class,但是比abstract class更加抽象,
考虑一个概念抽象方法。抽象方法用来描述系统提供哪些功能,而不必关心具体的实现。
抽象类可以为部分方法提供实现,避免了在子类中重复实现这些方法,提高了代码的可重用性,这是抽象类的优势;而接口中只能包含抽象方法,不能包含任何实现。
一个类可以实现多个接口,这个就是接口的优势。
选择抽象类的时候通常是如下情况:需要定义子类的行为,又要为子类提供通用的功能

LinkedHashMap怎么实现的

HashMap + 双向链表

ArrayList 和 LinkedList 是如何实现的?

ArrayList:内部使用数组的形式实现了储存,实现了RandomAccess接口,因此对元素的随机访问速度非常快,因为是数组,所以ArrayList在初始化的时候,有初始大小10,插入新元素的时候会判断是否需要扩容,扩容的步长是0.5倍原容量,扩容方式是利用数组的复制,因此有一定的开销,另外,ArrayList在进行元素插入的时候,需要移动插入位置之后的所有元素,位置越靠前,需要位移的元素越多,开销越大,相反,插入位置越靠后的话,开销就越小了,如果在最后面进行插入,那就不需要进行位移。 LinkedList:内部使用双向链表的结构实现储存,LinkedList有一个内部类作为存放元素的单元,里面有三个属性,用来存放元素本身以及前后2个单元的引用,另外LinkedList内部还有一个header属性,用来标识起始位置,LinkedList的第一个单元和最后一个单元都会指向header,因此形成了一个双向的链表结构LinkedList的元素并不需要连续存放,但是每个存放元素的单元比元素本身需要更大的空间,LinkedList对空间的要求比较大,但是扩容的时候不需要进行数组复制,因此没有这一环节的开销但是,LinkedList的随机访问速度惨不忍睹,因为无论你要访问哪一个元素,都需要从header起步正向或反向的进行元素遍历。 由此可见,ArrayList适合需要大量进行随机访问或者对靠近集合中尾部的元素进行增删的场景;而LinkedList则适合对靠近集合首部的元素进行增删的场景。

ArrayList 如何添加元素的?删除元素后会自动缩小空间吗?如果给你设计api 。除了目前的增删改查等等。你还有什么其他的想法。设计出其他的api.

将值置入,不会。可以自行调用 trimToSize。改造成 HashMap

Set 如何实现? 插入和删除和查找的时间复杂度是什么?

Set都是用对应的Map实现的。比如HashSet是由HashMap实现的,TreeSet是由TreeMap实现的。
只要将map的value都设置成null,那么它们的key就组成了一个Set

红黑树的左旋和右旋?

如果右子结点是红色的而左子结点是黑色的,进行左旋转
如果左子结点是红色的且它的左子结点也是红色的,进行右旋转
如果左右子结点均为红色,进行颜色转换
仔细看,这些操作的本质就是 把红链接上移
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值