一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情。
LinkedList集合的查询操作
LinkedList不支持数据的随机访问,通过一个索引位可以直接获取到数据。LinkedList的查询可以分为两种:
-
通过index查询,因为LinkedList底层是双向链表,所以它查询指定索引的方式,就是从头到尾部或者从尾部到头部进行遍历;具体看index是在前半段还是后半段,从而判断是从头开始遍历还是从尾部开始遍历;
-
根据指定的数据对象引用信息查询索引位,比如indexOf(Object),这个方法需要区分传入的对象是否为空,进行分别处理;
- 如果传入的object 为空,那么从头节点开始向后遍历,直到发现某个item属性值为null的节点
- 如果当前传入的object不为空,那么从头节点开始向后遍历,直到发现某个item的值与传入的object相等,这里的相等指的是equals()方法为true;
LinkedList的集合查询操作是比较简单的,我们就不展开讨论了,对这块有疑问的朋友可以留言给我,我们具体讨论。
LinkedList集合的栈特性
LinkedList除了实现List接口还实现了Deque接口。Deque是双端队列,支持从队列的两端独立检索和添加节点,因此Deque接口即支持LIFO操作模式,有支持FIFO操作模式。下表为Deque的重要操作。
| 方法 | 说明 |
|---|---|
| addFirst(E) | 双向链表的头部增加节点 |
| addLast(E) | 双向链表的尾部添加节点 |
| getFirst() | 获取头部节点,没有节点的话会抛出异常 |
| getLast() | 获取尾部节点,没有节点的话会抛出异常 |
| peekFirst() | 获取头部节点,没有节点的话返回null,注意不移除 |
| peekLast() | 获取尾部节点,没有节点的话返回null,注意不移除 |
| push(E) | 向栈顶放入一个新的数据对象 |
| pop() | 从栈顶移出数据对象 |
| removeFirst() | 从双向链表头部移出数据对象,同pop |
| removeLast() | 从双向链表尾部移出数据对象 |
| pollFirst() | 从头部移除对象,并返回头部对象 |
| pollLast() | 从尾部移除对象,并返回尾部对象 |
LinkedList和ArrayList的对比
-
底层数据结构层面分析:
- LinkedList底层为双向链表,不支持随机访问
- ArrayList底层数据结构为数组,支持随机访问
-
性能层面分析
-
读
- ArrayList底层实现为数组,支持随机访问,可以直接根据索引位获取数据对象,时间复杂度O(1)
- LinkedList底层实现为双向链表,如果获取的是头部节点或者尾部节点,不存在额外的消耗,直接获取对象即可
- LinkedList查询性能较差的情况是获取中间部位的数据,这个时候无论是从头部获取还是从尾部获取,时间复杂度都是O(n)
-
写
- ArrayList如果是写入数组的前部,那么需要进行数组的拷贝,需要额外的消耗
- ArrayList如果是写入数组的尾部,那么需要判断尾部是否有额外的空间,如果有额外的空间,那么基本不存在什么消耗,但是如果没有额外的空间,那么需要进行扩容,额外的消耗较大
- LinkedList如果是写入头部或者是尾部,那么只需要修改头节点或者尾节点的引用即可,时间复杂度O(1)
- LinkedList如果是要写入中部,那么需要遍历到中部,然后再去修改引用;时间复杂度O(n)
-
LinkedList使用场景
通过上面的分析,我们得知,linkedList的写性能通常情况下要比ArrayList的写性能要好,所以当集合的写规模远大于读规模操作,尤其是这种写并不是在尾部写的情况下我们推荐使用LinkedList,其他情况我们推荐使用ArrayList;