问题
(1)LinkedList只是一个List吗?
(2)LinkedList还有其它什么特性吗?
(3)LinkedList为啥经常拿出来跟ArrayList比较?
(4)我为什么把LinkedList放在最后一章来讲?
简介
LinkedList是一个以双向链表实现的List,它除了作为List使用,还可以作为队列或者栈来使用,它是怎么实现的呢?让我们一起来学习吧。
UML继承关系
通过继承体系,我们可以看到LinkedList不仅实现了List接口,还实现了Queue和Deque接口,所以它既能作为List使用,也能作为双端队列使用,当然也可以作为栈使用。
源码分析
主要属性
1 | // 元素个数 |
属性很简单,定义了元素个数size和链表的首尾节点。
主要内部类
典型的双链表结构。
1 | private static class Node<E> { |
主要构造方法
1 | public LinkedList() { |
两个构造方法也很简单,可以看出是一个无界的队列。
添加元素
作为一个双端队列,添加元素主要有两种,一种是在队列尾部添加元素,一种是在队列首部添加元素,这两种形式在LinkedList中主要是通过下面两个方法来实现的。
1 | // 从队列首添加元素 |
典型的双链表在首尾添加元素的方法,代码比较简单,这里不作详细描述了。
上面是作为双端队列来看,它的添加元素分为首尾添加元素,那么,作为List呢?
作为List,是要支持在中间添加元素的,主要是通过下面这个方法实现的。
1 | // 在节点succ之前添加元素 |
在中间添加元素的方法也很简单,典型的双链表在中间添加元素的方法。
添加元素的三种方式大致如下图所示:
在队列首尾添加元素很高效,时间复杂度为O(1)。
在中间添加元素比较低效,首先要先找到插入位置的节点,再修改前后节点的指针,时间复杂度为O(n)。
删除元素
作为双端队列,删除元素也有两种方式,一种是队列首删除元素,一种是队列尾删除元素。
作为List,又要支持中间删除元素,所以删除元素一个有三个方法,分别如下。
1 | // 删除首节点 |
删除元素的三种方法都是典型的双链表删除元素的方法,大致流程如下图所示。
在队列首尾删除元素很高效,时间复杂度为O(1)。
在中间删除元素比较低效,首先要找到删除位置的节点,再修改前后指针,时间复杂度为O(n)。
栈
前面我们说了,LinkedList是双端队列,还记得双端队列可以作为栈使用吗?
1 | public void push(E e) { |
栈的特性是LIFO(Last In First Out),所以作为栈使用也很简单,添加删除元素都只操作队列首节点即可。
总结
(1)LinkedList是一个以双链表实现的List;
(2)LinkedList还是一个双端队列,具有队列、双端队列、栈的特性;
(3)LinkedList在队列首尾添加、删除元素非常高效,时间复杂度为O(1);
(4)LinkedList在中间添加、删除元素比较低效,时间复杂度为O(n);
(5)LinkedList不支持随机访问,所以访问非队列首尾的元素比较低效;
(6)LinkedList在功能上等于ArrayList + ArrayDeque;
彩蛋
java集合部分的源码分析全部完结,整个专题以ArrayList开头,以LinkedList结尾,我觉得非常合适,因为ArrayList代表了List的典型实现,LInkedList代表了Deque的典型实现,同时LinkedList也实现了List,通过这两个类一首一尾正好可以把整个集合贯穿起来。
还记得我们一共分析了哪些类吗?
下一章,笔者将对整个java集合做一个总结,并提出一些阅读源码过程中的问题,敬请期待^^