集合
TreeSet
基于红黑树,支持有序操作。底层是TreeMap实现的(add方法是调用TreeMap的 put方法),TreeMap的put()方法内部是 通过comparato 进行比较大小和排序。TreeSet内部需要对元素进 行排序,因此元素需要实现Comparable接口。如果没有实现则会抛出异常。不能放入null元素。
HashSet
hashSet基于哈希表,不支持有序。遍历的结果是不确定的。底层是HashMap实现的,add()方法是HashMap的put()方法实现的。
LinkedHashSet
具有hashSet的查找效率,同时内部使用双向链表维护元素的插入顺序。继承于hashSet,底层基于LinkedHashMap来保存所有的元素,其所有的方法操作上与hashSet相同。
ArrayList
- arrayList实现了List接口,是有序的。除了未实现同步以外,其余跟Vector大致相同。每一个arrayList都有一个初始容量,表示底层数据的实际大小,当向容器中添加元素的时候,
- 如果容量不足,会自动扩容。
- 底层是数组。
- 自动扩容,每当向数组添加元素的时候,都会检查添加后的元素个数是否会超过当前数组的长度,如果超出,将会数组扩容。数组扩容的时候,会将老数组复制一份到新数组中,数组扩容通过ensureCapacity()方法来进行,每次数据增长大约是原来的1.5倍,这种代价是很高的。可以预先指定数据容量,或者手动调用ensureCapacity()方法扩容。
-
add(),addAll(),get(),set(),indexOf(),lastIndexOf(),remove()
- 快速失败机制:arrayList采用快速失败机制,通过记录modCount参数来实现。在面对并发修改时,迭代器很快就会失败,而不是冒着风险。modCount :修改次数,对数组的修改都会增加modCount的值,在迭代器初始化的时候,会传递此参数给迭代器的expectedModCount,在迭代过程中,会比较两者是否相等,如果不相等就代表有其他线程修改了。注意:modCount使用了volatile修饰,保证线程之间的可见性。
LinkedList
- 同时实现了List和deque接口,可以将它看做是一个有序的容器,也可以看做队列和栈。为了追求效率没有使用同步
- 底层是通过双向链表来实现的
- getFirst(),getLast(),remove(),add()等方法
java7 hashMap
- hashMap继承了Map,允许key和value为null的元素,除了未实现同步以外,跟hashTable相似。跟TreeMap不同,它不保证元素的顺序。根据需要可能会对元素重新hash,元素的顺序可能会被打乱,因此不同时间迭代同一个hashMap顺序可能会不一样。根据处理哈希冲突方式的不同,java7 hashMap采用冲突链表的方式。
- 在对hashMap遍历的时候,需要对整个table以及后面跟的冲突链表,对于迭代频繁场景,不宜设置初始大小过大。
- 有两个参数对hashMap性能影响比较大,初始容量和负载因子。初始容量指定了初始table大小。负载因子指定扩容的临界值。对于插入场景比较多,可以设置大一点负载因子,减少扩容次数。
- get() ,根据指定的key返回对应的value,调用了getEntry()得到相应的entry,然后返回entry.value()。getEntry()算法的思想是通过hash()函数得到对于数组下标,然后遍历冲突链表。通过equals()判断是否是要找的entry。
- put(), 是将指定的key放到map里,该方法首先对map进行一次查找,看是否包含该元素,如果已经包含则返回,查找过程类似getEntry(),如果没有找到,则调用addEntry()方法插入新的entry,插入方式为头插法。
java8 hashMap
- java8对hashMap最大的不同就是利用了红黑树,所以其由数组+链表+红黑树组成。在java7的介绍中,根据hash值我们能够快速定位到数组的下标,但之后,就要顺着链表一个比较下去才能找到我们锁需要的,时间复杂度取决于链表的长度。
- 为了降低这部分的开销,在java8中,当链表元素达到了8个时,会将链表转换为红黑树。
- get过程分析,计算key的hash值,根据hash值找到对应数组下标,判断该数组是否是刚好要找的,如果不是,继续。
- 判断该元素是否是TreeNode,如果是。用红黑树的方法取数据,如果不是,下一步
- 遍历链表,equasl()方法找
hashSet:hashSet是对hashMap的简单包装,对hashSet的函数调用都会转换成合适的hashMap方法。
LinkedHashSet和LinkedHashMap
- linkedHashSet和linkedHashMap有着相同的实现,前者仅仅是对后者做了一层包装。
- LinkedHashMap实现了Map接口,即允许放入key和value为null的元素。
- LinkedHashMap是hashMap的直接子类,采用双向链表的形式将所有entry连接起来,这样是为了保证元素的迭代顺序跟插入顺序是一样的。
- 采用双向链表还有一个好处:迭代时不需要向hashMap一样遍历整个table,而只需要直接遍历header指向的双向链表即可,迭代时间跟entry个数相关。
- 对linkedHashSet的函数调用都会转换成合适的linkedHashMap方法
TreeSet和TreeMap
- 二者在java里面有着相同的实现,前者仅仅是对后者做了一层包装,也就是说treeSet里面有一个treeMap。
- TreeMap实现了SortedMap接口,也就是说会按照key的大小顺序对Map中的元素进行排序,TreeMap底层通过红黑树实现,也就意味着get,put,remove都有log(n)的时间复杂度
- 红黑树是一种近似平衡的二叉查找树,a.每个节点要么是红色,要么是黑色 b.跟节点是黑色的 c.红色节点不能连续 d.对于每个节点,从该节点至任何路径都含有相同个数黑色节点。
- 在树结构发送变化时,往往会破坏上述条件c或者d,需要通过重新调整使得查找重新满足红黑树的条件
- 左旋:左旋的过程就是将X的右子树绕X逆时针旋转,使得X的右子树成为X的父亲,同时修改相关节点的引用。旋转后,二叉数的属性任然满足。
- 右旋:是将X的左子树顺时针旋转,使得X的左子树成为X的父亲,同时修改相关引用,旋转之后,二叉树仍然满足。
- get()方法:根据指定的key查找对应的value,该方法调用了getEntry()得到相应的entry。因此getEntry()是算法的核心,核心思想是根据key的自然顺序对二叉树进行查找,直到满足compareTo == 0 的 entry
- put()方法:将指定的key,value添加到map里面,该方法首先对map进行一次查找,看是否包含该元组,如果包含直接返回,查找过程类似getEntry()方法,如果没有找到则会在红黑树中插入新的entry(),如果破坏了红黑树的约束条件,需要进行调整。
没有目标的日子都是在摆烂,都是虚度光阴,都是在自我欺骗

浙公网安备 33010602011771号