引言
昨天介绍了java集合类框架,接下来会详细聊一下各个集合类的适用场景和需要注意的地方。今天主要介绍一下List,如有错误之处,还望指正。
List
List 是java集合中最简单,也是最常用的一种集合。List存储的是一种有序、不重复的数据。比如产品列表、商品列表等等。ArrayList和LinkedList是比较常用的List集合类。今天主要是聊一聊这两种List的具体实现以及适用场景。
ArrayList
ArrayList常用增删改查操作如下:
ArrayList的底层实现是一个数组,默认的构造函数new ArrayList<>(),数组的容量为10。当调用add()或者add(index,value)方法的时候。首先要判断数组的是否超过容量,不然需要扩容长度。扩容的逻辑是在原有的长度上,增加1/2,也即原来如果是10的话,第一次扩容的长度是15,用Arrays.copyOf()方法复制一个新的容量为新长度数组出来,复制给原先的数组。如果扩充的长度超过Integer.MAX_VALUE时会报OutOfMemoryError。
增:ArrayList有两种增加元素的方法,在数组的末尾直接添加元素即add(element)。还有一种方式是在指定的index上添加元素,此时如果该index上有元素,当前元素和后续元素都需后移,时间复杂度为O(N)。
删:ArrayList有两种删除元素的方法,按元素值删除和按index删除。按值删除,首先需要找到元素值得位置,这里要注意的是,自定义对象要实现equals方法,因为决定元素值是否相等取决于equals的返回值。找到位置后,该位置后续的所有元素都要前移,时间复杂度为O(n)。按index删除,根据index找到位置,该位置后面所有的元素前移,时间复杂度为O(n)。
改:ArrayList的修改操作比较简单,直接在数组的index,把新的值赋值给所在的index即可,时间复杂度为O(1)。
查:直接根据index,找到位置取出值即可。
结论:
1、ArrayList适合创建前能预估容量大小的场景
2、ArrayList适合于查询和更改比较多的场景,不适合删除比较多的场景
3、在使用按值删除操作时,需实现equals方法。个人建议,自定义对象默认都要实现equals和hashCode方法,不然容易掉坑里面。
LinkedList
LinkedList常用的增删改查操作如下:
可以看到的是和ArrayList调用的方法是一样的。但是实现原理是不一样的。LinkedList的实现原理是一个链表。
增:LinkedList同样有两种增加元素的方法,在链表尾部增加元素和指定index增加元素,在尾部增加元素,直接在last节点增加节点,重新复制last即可,时间复杂度为O(1).指定index增加元素,相比ArrayList多了个寻找index的操作,但是不需要移动元素,只需更改结点之间的指向关系就可以,时间复杂度为O(n)(不是通常认为的O(1),好多人认为是O(1)。
删:LinkedList同样两种删除元素的方法,按元素值删除和按index删除。
按值删除,与ArrayList类似,不同的是元素不需要移动,时间复杂度为O(n)。按index删除,根据index找到元素后,也不需要移动元素,时间复杂度为O(n)。
改:根据index找到位置后,更新值。这个比较简答,没什么可说的,时间复杂度也是O(1)。
查: LinkedList的查询相对于ArrayList复杂度就比较高,LinkedList需要移动指针找到查询的元素,时间复杂度为O(1)。
结论:
1、LinkedList不需要连续的内存,分散的内存空间也可以。ArrayList是必须要连续的存储空间的。此外LinkedList没有扩容这么一说。
2、LinkedList增加和删除没有涉及元素的移动,相对ArrayList是比较合适的,但是不适合查询。
此外,LinkedList不仅仅用做List,还被经常用作队列和栈。队列是一种先进先出FIFO的数据结构。栈是一种先进后出FILO的数据结构。这两种数据结构是计算机中使用比较频繁的数据结构,后续有空再详细介绍
如果觉得文章还不错,欢迎关注、转发、评论。
网友评论