Java Collection 框架 LinkedList 源码解读 与 实现原理 浅析


 

上一篇我们简单了解了ArrayList的底层原理,当插入与删除时,可能每次都需要移动其底层整个数组内的元素,速度通常很慢,但是好处也很明显通过数组结构进行访问查找时,通过指针可以快速定位元素。

 

今天继续来看一下LinkedList的底层原理。

 

LinkedList本质上是一个双向链表,与ArrayList对比,LInkedlist插入与删除速度快,但是访问速度慢,是按照链路顺序查找的线性结构,可以将零散的内存串联起来,内存利用效率高。

 

java list批量查询数据库并合并返回结果_赋值


 

接下来看一下LInkedList的源码,看看LinkedList的底层数据结构是什么样子的。

 

java list批量查询数据库并合并返回结果_LinkedList_02


 

LinkedList包含了三个成员变量,都用transient关键字来使其在序列化时被忽略,size指的是尺寸大小,first记录链表的第一个节点Node,last记录链表的最后一个节点Node,与ArrayList不同,LinkedList

不是以数组为底层数据结构,而是使用Node节点,接下来我们来看一下LinkedList记录元素的基本单位Node类。

 

java list批量查询数据库并合并返回结果_LinkedList_03


 

Node类是一LinkedList的一个内部私有类,内部有三个成员变量,item即需要存储的元素本身,next为当前节点的下一个节点,perv为当前节点的前一个节点,Node的构造器为存储这三个参数。通过next与perv,LinkedList便可以让Node节点串联起来。

 

接下来我们看一下LinkedList的几个特有方法:

 

addFirst();

 

addFirst在头部添加一个节点。

 

java list批量查询数据库并合并返回结果_链表_04


 

实际上调用了linkFirst的方法。

 

java list批量查询数据库并合并返回结果_链表_05


 

取出第一个节点赋值给f,创建新节点,参数perv节点为空,将f当做新节点的next节点,并把创建的新节点赋值给LinkedList的first变量。

 

如果f为空,则LinkedList为空链表,将last节点也指向newNode。如果f不为null,就将f的前一个节点指向newNode。size++。

 

addLast();

 

java list批量查询数据库并合并返回结果_链表_06


 

addLast实际调用了linkLast(e);

 

java list批量查询数据库并合并返回结果_java_07


 

原理同linkFirst,这里不再赘述。

 

offerFirst()与offerLast()

 

java list批量查询数据库并合并返回结果_java_08


 

JDK1.6之后加入了offerFirst();与offerLast(),调用了addFirst与addLast,底层还是调用linkFirst与linkLast,添加了返回布尔值。

 

接下来看一下LinkedList对于add,set,remove,get接口方法的实现。

 

public boolean add(E e)

 

java list批量查询数据库并合并返回结果_链表_09


 

 

public void add(E e)方法,实际上调用了linkLast,向链表的尾部添加元素。

 

public boolean remove(Object o)

 

java list批量查询数据库并合并返回结果_LinkedList_10


 

remove方法实际上为for循环遍历链表找到指定元素后执行unlink方法。

 

java list批量查询数据库并合并返回结果_LinkedList_11


 

unlink方法,取指定节点Node,然后指定节点如果没有prev,则执行其next为first。如果prev不为null则将前一个节点的next指定为指定节点的next节点,这样来使要被remove的节点的前后两个节点链接起来。

 

如果next为null则执行将last指向被删除Node的prev,如果不为null则将下一个被删除Node的下一个节点的prev指向被删除节点Node的prev保证链接。

 

最后将x.item赋值为null,size尺寸减一。最后返回被删除节点的元素。

 

java list批量查询数据库并合并返回结果_集合_12


 

再来看removeFirsr与removeLast方法。调用了unlinkFirst与unlinkLast。

 

java list批量查询数据库并合并返回结果_链表_13


 

原理同上不再赘述,这里粘出源码,大家可以自己读一下。接下来我们看一下get方法。

 

java list批量查询数据库并合并返回结果_赋值_14


 

get方法需要传入index指针首先会先check指针的合法性,然后调用node(index)方法获取元素。

 

java list批量查询数据库并合并返回结果_java_15


 

这个方法实际上就是遍历整个链表,但是这里会根据index来判断距离头部节点近还是距离尾部节点近来决定从头还是尾进行遍历查找。

 

在使用get方法的时候,index从哪里来呢?所以这里还要使用public int indexOf(Object o)来获取节点指针。

 

java list批量查询数据库并合并返回结果_LinkedList_16


 

同样通过for循环遍历计算index,所以说在使用查询和查找Linkedlist元素时,效率没有ArrayList高,因为需要遍历整个链表。

 

JDK1.5之后加入了peek,poll,element,remove方法,用于获取头部和,或者获取后删除元素,实际上这是Queue队列性质的操作。

 

java list批量查询数据库并合并返回结果_链表_17


 

JDK1.6加入了Deque operations双端队列操作,这些方法的基础方法上面都已经说过了,这里源码比较简单就不再赘述。

 

java list批量查询数据库并合并返回结果_java_18


java list批量查询数据库并合并返回结果_赋值_19


 

LinkedList最大的好处在于头尾和已知节点的插入和删除时间复杂度都是o(1)只需要一次操作即可。

 

但是涉及到先确定位置再操作的情况,则时间复杂度会变为o(n)线性级,随着数据的增多,耗时也会增加。

 

此外,每个节点都需要保留prev和next指针也浪费了空间。

 

LinkedList本身也有迭代器的实现,原理与上述方法差不多,这里感兴趣可以自行查看源码,也是对于链表和节点的操作,这里不再赘述。

 

以上就是关于LInkedList底层原理的浅析。