Java集合概览
Java集合,也叫做荣去,主要是由两大接口派生而来:一个是 Collection
接口,主要用于存放单一数据;另一个是 Map
接口,用于存放键值对。对于 Collection
接口,下面又有三个主要的子接口:List
Set
Queue
List
对于 List
子接口,有两个重要的实现类,一个是 ArrayList
,另一个是 LinkedList
ArrayList
ArrayList 集合的底层数据结构是一个数组,利用 elementData
来存放数据。再创建 ArrayList
集合对象的时候,只是给 elementData
赋值了一个长度为 0
的空数组的,并没有给定长度,除非我们直接使用带有参的创建方法创建 ArrayList
对象。
这个长度为 0 的空数组,只有在我们第一次调用 add()
方法的时候,才会对 ArrayList
集合进行扩容,扩充到长度 10 ,并且会记录集合的修改次数。
在后续添加元素的过程中,如果集合长度不够,需要扩容,ArrayList
底层使用的是 老数组长度 + 老数组长度右移一位得到一个新数组的长度,并且通过复制的方法把老数组中的元素复制到新数组中。
ArrayList 插入和删除元素的时间复杂度:
对于插入
-
头部插入:由于需要将所有元素都一次向后移动一个位置,因此时间复杂度是 O(n)。
-
尾部插入:当
ArrayList
的容量未达到极限时,往列表末尾插入元素的时间复杂度是 O(1),因为它只需要在数组末尾添加一个元素即可;当容量已达到极限并且需要扩容的时,则需要执行一次 O(n) 的操作将原数组复制到新的更大的数组中,然后再执行 O(1) 的操作添加元素 -
指定位置插入:需要将目标位置之后的所有元素都向后移动一个位置,然后再把新元素放入指定位置,这个过程平均需要移动 吗、n/2 个元素,因此使劲啊复杂度未 O(n);
对于删除:
-
头部删除:由于需要将所有元素依次向前移动一个位置,因此时间复杂度是 O(n)。
-
尾部删除:当删除的元素位于列表末尾时,时间复杂度为 O(1)。
-
指定位置删除:需要将目标元素之后的所有元素向前移动一个位置以填补被删除的空白位置,因此需要移动平均 n/2 个元素,时间复杂度为 O(n)。
ArrayList 和 LinkedList 区别
-
是否保证线程安全:
ArrayList
和LinkedList
都是不同步的,也就是不保证线程安全; -
底层数据结构:
ArrayList
底层使用的是Object
数组;LinkedList
底层使用的是 双向链表 数据结构(JDK 1.6 之前为循环链表,JDK 1.7 之后取消了循环) -
插入和删除是否受元素位置的影响:
-
ArrayList
采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。比如:执行add()
方法的时候,ArrayList
会默认在将指定的元素追加到此列表的末尾,这种情况的时间复杂度就是 O(1) 但是如果要在指定位置 i 插入和删除元素的话 (add(int index , E e)
,时间复杂度就是 O(n)。 因为在执行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后/向前移一位的操作。 -
LinkedList
采用链表存储,所以在头尾插入或者删除元素不受元素位置的影响、时间复杂度为O(1), 如果是要在指定位置插入元素的话,时间复杂度为 O(n) ,因为需要先移动到指定位置再插入和删除。
-
-
是否支持快速随机访问:
LinkedList
不支持搞笑的随机元素访问,而ArrayList
实现了RandomAccess
接口,所以ArrayList
支持快速随机访问,快速随机访问就是通过元素的需要快速获取元素对象的方法(get(int index)
) -
内存空间占用:
ArrayList
的空间浪费主要体现在 list 列表的结尾会预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要想好比 ArrayList 更多的空间。