[Java]深入底层聊LinkedList——简单全面,深入底层的最好开始

书接上文ArrayList,我们话不多说直接开整。

LinkedList

我们在学习容器类List的时候都知道,ArrayList适用于读,在查询指定内容时要比LinkedList快的多。而LinkedList则适用于写,在向容器中插入内容时要比ArrayList快的多。
是什么导致了这两者之间的不同呢?那肯定是底层实现喽。从上一篇文章我们了解到,ArrayList底层是使用数组进行实现的,我们在插入元素时要进行数组扩充(创建新的数组,把原始数组的内容复制到新的数组),这一过程耗费大量的时间。在查询元素时情况就大不相同了,因为数组的地址连续,他直接以数组下标为索引,返回elementData[i]就可以了。那么LinkedList的底层又是怎么实现的呢?接下来我们从源码慢慢分解
在这里插入图片描述
在这里插入图片描述
从源码中可以看到,LinkedList的底层时使用,链表来实现的。每一个LinkedList对象都持有一个first,一个last指针,他们分别指向链表的第一个节点和最后一个节点。而且从节点(Node)的数据结构来看的话,一个节点有两个指针域,一个next,一个prev,分指向该节点的后继和前驱,item是数据域。这样看来的话LinkedList的底层是用双向链表实现的无疑了。我们都知道链表的特点就是适合插入(不需要移动元素,只需要改变一下指针指向就可以了)元素,不适合查找(查找第i个元素必须从第一个元素开始遍历,直到找到第i个元素为止)元素的。
虽然知道了为什么LinkedList为什么适合写不适合读了,但我们还是要看看每个方法的源码的实现是否跟我们想象的一样,或者有什么特别之处呢
add(E elem)方法(在末尾插入元素)
在这里插入图片描述
我们每次调用add(E elem)方法,源码内部都会最终调用linkedLast方法在链表的后面加入元素。linkedLast其实跟我们写链表的代码没有任何区别。创建一个l的指针指向last节点->创建一个新的节点newNode(pre指针域,指向l节点,数据为e,next指针指向null)->last指向newNode->判断该链表是否为空,如果为空就令first指针指向newNode,如果不为空就领l.next指向newNode->size自增,modCount自增(modCount跟size一样表示该链表中数据的个数,只是modCount是在迭代器中使用的)
get(int index)(查询第i个数据元素)
在这里插入图片描述
就先检查输入的index是不是合法,然后调用node(i)方法,返回对应节点后.item
在这里插入图片描述
可以看到,node(int i)方法也没有什么特别之处,就是顺序遍历节点。不同的是它给出了优化:如果index < size /2则从头向后遍历,如果 index >= size / 2则从后向前遍历。这样设计在一定程度上会大幅度减少遍历所耗费的时间。
remove(E elem)(删除指定元素)
在这里插入图片描述
逻辑很简单。先找到含有指定元素的节点,如果找不到就返回false找到了就调用unlink(Note x)方法断开连接。
在这里插入图片描述
断开连接度过程也比较简单,找到其前驱和后继节点,然后使前驱节点和后继节点相连。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章