List集合之LinkedList原理剖析二

352 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情

LinkedList集合的查询操作

LinkedList不支持数据的随机访问,通过一个索引位可以直接获取到数据。LinkedList的查询可以分为两种:

  1. 通过index查询,因为LinkedList底层是双向链表,所以它查询指定索引的方式,就是从头到尾部或者从尾部到头部进行遍历;具体看index是在前半段还是后半段,从而判断是从头开始遍历还是从尾部开始遍历;

  2. 根据指定的数据对象引用信息查询索引位,比如indexOf(Object),这个方法需要区分传入的对象是否为空,进行分别处理;

    1. 如果传入的object 为空,那么从头节点开始向后遍历,直到发现某个item属性值为null的节点
    2. 如果当前传入的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的对比

  1. 底层数据结构层面分析:

    1. LinkedList底层为双向链表,不支持随机访问
    2. ArrayList底层数据结构为数组,支持随机访问
  2. 性能层面分析

      1. ArrayList底层实现为数组,支持随机访问,可以直接根据索引位获取数据对象,时间复杂度O(1)
      2. LinkedList底层实现为双向链表,如果获取的是头部节点或者尾部节点,不存在额外的消耗,直接获取对象即可
      3. LinkedList查询性能较差的情况是获取中间部位的数据,这个时候无论是从头部获取还是从尾部获取,时间复杂度都是O(n)
      1. ArrayList如果是写入数组的前部,那么需要进行数组的拷贝,需要额外的消耗
      2. ArrayList如果是写入数组的尾部,那么需要判断尾部是否有额外的空间,如果有额外的空间,那么基本不存在什么消耗,但是如果没有额外的空间,那么需要进行扩容,额外的消耗较大
      3. LinkedList如果是写入头部或者是尾部,那么只需要修改头节点或者尾节点的引用即可,时间复杂度O(1)
      4. LinkedList如果是要写入中部,那么需要遍历到中部,然后再去修改引用;时间复杂度O(n)

LinkedList使用场景

通过上面的分析,我们得知,linkedList的写性能通常情况下要比ArrayList的写性能要好,所以当集合的写规模远大于读规模操作,尤其是这种写并不是在尾部写的情况下我们推荐使用LinkedList,其他情况我们推荐使用ArrayList;