LinkedList
linkedList 也是 list 接口底下的实现类 , 底层是双向链表, 具有增删快的优点
通过jdk 源码可以看到 , LinkedList 也实现了 Deque , 这说明你也可以将 LinkedList 看成一个队列或者一个栈 , 它具有这些的所有特性
底层结点类如下 :
可见它是一个双向链表
在LinkedList中的 add() 方法里, 我们不涉及到扩容这些问题, 因为只要内存够大, 只需改变指针位置,就可以一直添加下去 , jdk1.8 源码如下
如上图 , 先让 L 记录尾元素,构造新结点, 然后将尾元素的next 指向新结点即可
接着来谈 Deque , 我们知道 , Deque是一个双端队列接口 ,而 LinkedList 实现了它, 也就意味着我们的 LinkedList 也可以当做一个队列 或者 栈来使用 , 那么如何去使用呢
来看 Deque 接口 提供的一些方法
boolean offer(E e) : 将元素 e 插入双端队列尾部 (进队), 插入成功返回true , 空间不足返回false
boolean offerFirst(E e) : 将元素 e 插入双端队列头部 , 插入成功返回true , 否则false
boolean offerLast(E e) : 与offer(E e) 效果相同
E poll() : 从双端队列中取出队头元素(出队), 队列为空则返回 null
E pollFirst() : 与 poll() 效果相同
E pollLast() : 从双端队列中取出队尾元素 , 队列为空返回 null
E peek() : 取双端队列的队头元素,(仅仅拿到值,不出队)
E peekFirst() : 与peek() 相同
E peekLast() : 取双端队列的队尾元素, 为空返回 null
从提供的这些方法可以看出 ,
如果我们只使用 offer() 与 poll() 或者 offFirst() 与 pollLast() 时 ,那么我们的LInkedList相当于一个单向队列(只在一端进,另一端出)
如果我们只使用 offer() 与 pollLast() 或者 offerFirst() 与 peek() 时 , 那么此时我们的LinkedList又相当于一个栈 (只在一端同时进出)
最后我们再来看 LinkedList 提供的这样一个方法 : get(int index)
通过方法名 , 我们可以了解到 ,它是通过索引来获取元素值 , 但此处的 index 也不能称作为"索引", 此处更应该 叫做 一个"记录" , 因为索引是向 ArrayList那样,我们可以通过它来直接拿到元素,而LinkedList显然不行
接着我们来看源码解析
public E get(int index) {
//先检查索引的合法性
checkElementIndex(index);
return node(index).item;
}
Node<E> node(int index) {
// assert isElementIndex(index);
// 如果 index 小于 size的一半长度时,就从前往后找
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
// 通过for 循环一直往下找满足条件的结点
x = x.next;
return x;
// index 大于 size的一半时,从后往前找
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
通过源码可以发现 , LinkedList的缺点显而易见 , 查找元素需要从前往后(或者从后往前) 一直比对,所以它的查找元素功能相对来说就是比较慢的 , 而 使用ArrayList 可以直接通过索引找到所需要的值 , 但ArrayList 的新增和删除元素又牵扯到扩容和元素移动这些问题 ,LinkedList却没有 ,所以在 新增和删除方面 , LinkedList占优, 在元素查找方面 , ArrayList占优
那么关于 LinkedList就先讨论到这 ,关于ArrayList 可以参考