概述
_LinkedList_
同时实现了_List_
接口和_Deque_
接口,也就是说它既可以看作一个顺序容器,又可以看作一个队列,,同时又可以看作一个栈. 所以当需要使用队列或是栈结构时,可以考虑使用LinkedList
.
LinkedList的实现方式决定了所有跟下标相关的操作都是线性时间,而在首段或者末尾操作则是常数时间.
由于LinkedList
没有实现同步,所以直接使用多线程访问可能造成线程不安全问题,解决方法为,在定义LinkedList
是使用Collections.synchronizedList()
对其进行包装
List list=Collections.synchronizedList(new LinkedList(...));
特点
- LinkedList 基于链表实现
- 是线程不安全的
- LinkedList 可以被当作堆栈、队列或双端队列进行操作。
- LinkedList 实现
List
接口,所以能对它进行队列操作。- LinkedList 实现
Deque
接口,能将LinkedList当作双端队列使用。- LinkedList 实现了
Cloneable
接口,即覆盖了函数clone(),能克隆。- LinkedList 实现
java.io.Serializable
接口,所以LinkedList支持序列化,
内部结构
LinkedList
底层通过双向链表实现,每个节点使用内部类Node表示,内部通过first
和last
指针分别指向链表头和链表尾,内部不存在为空的头尾节点,也就是说当LinkedList
为空时,上述两个指针都指向null
private static class Node<E> {
E item; //当前节点值
Node<E> next; //前驱节点
Node<E> prev; //后继节点
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
内部源码
构造方法
1.空构造器
/**
* Constructs an empty list.
*/
public LinkedList() {
}
2.使用集合构造LinkedList
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
插入方法
add(E e)
将元素添加到链表尾部
/**
* Appends the specified element to the end of this list.
*
* <p>This method is equivalent to {@link #addLast}.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
linkLast(e); //连接到链表尾
return true;
}
/**
* Links e as first element.
*/
void linkLast(E e) {
final Node<E> l = last; //暂存旧尾
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode; //旧尾中next指针指向新尾
size++;
modCount++;
}
add(**int **index, E element)
将元素插入到index位置处
/**
* Inserts the specified element at the specified position in this list.
* Shifts the element currently at that position (if any) and any
* subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
checkPositionIndex(index); //检查索引是否处于[0-size]之间
if (index == size) //下标等于size证明需要插入到尾部
linkLast(element);
else
linkBefore(element, node(index)); 不等于则插入到指定的node
}
不等于时调用linkBefore(element, node(index));
在index号元素之前插入元素(插入后element变为index号元素)
void linkBefore(E e, Node<E> succ) {
// assert succ != null; succ由node(index)方法计算而来,所以断言不为空
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
node(index)
寻找到下标为index的节点
/**
* Returns the (non-null) Node at the specified element index.
返回一个node,保证不为null
*/
Node<E> node(int index) {
// assert isElementIndex(index); //调用前做过校验所以断言存在index号元素
if (index < (size >> 1)) {//由于链表下标操作为线性时间,所以采用二分查找下标降低时间复杂度
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
addAll(collection c)
集合插入链表尾部
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
调用addAll(int index,collection c)
将集合插入指定位置,传入参数为size,所以是将集合插入尾部
public boolean addAll(int index, Collection<? extends E> c) {
//1:检查index范围是否在size之内
checkPositionIndex(index);
//2:toArray()方法把集合的数据存到对象数组中
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
//3:得到插入位置的前驱节点和后继节点
Node<E> pred, succ;
//如果插入位置为尾部,前驱节点为last,后继节点为null
if (index == size) {
succ = null;
pred = last;
}
//否则,调用node()方法得到后继节点,再得到前驱节点
else {
succ = node(index);
pred = succ.prev;
}
// 4:遍历数据将数据插入
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
//创建新节点
Node<E> newNode = new Node<>(pred, e, null);
//如果插入位置在链表头部
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
//如果插入位置在尾部,重置last节点
if (succ == null) {
last = pred;
}
//否则,将插入的链表与先前链表连接起来
else {
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
addAll(int index,collection e)
的执行大致可分为四步
1.校验参数合法性
2.将集合中元素使用toarray
方法转换为数组
3.得到要插入位置的前驱后继节点(前一个节点的后继和后一个节点的前驱)
4.遍历数组,将元素插入到上述两个指针中
addFirst(E e)与AddLast(E e)
/**
* Inserts the specified element at the beginning of this list.
*
* @param e the element to add
*/
public void addFirst(E e) {
linkFirst(e);
}
/**
* Appends the specified element to the end of this list.
*
* <p>This method is equivalent to {@link #add}.
*
* @param e the element to add
*/
public void addLast(E e) {
linkLast(e);
}
二者都分别调用了 linkLast(e); linkFirst(e);
/**
* Links e as first element.
*/
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
/**
* Links e as last element.
*/
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
执行方式与linkBefore
类似
删除方法
remove() ,removeFirst(),pop(): 删除头节点
public E pop() {
return removeFirst();
}
public E remove() {
return removeFirst();
}
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
/**
* Unlinks non-null first node f.
*/
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC 没有关于此节点的应用 内存会被GC回收
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
remove()
实现的是ListIterator
接口,而removeFirst(),pop()
实现的是Depue
接口
removeLast(),pollLast(): 删除尾节点
/**
* Removes and returns the last element from this list.
*
* @return the last element from this list
* @throws NoSuchElementException if this list is empty
*/
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
/**
* Retrieves and removes the last element of this list,
* or returns {@code null} if this list is empty.
*
* @return the last element of this list, or {@code null} if
* this list is empty
* @since 1.6
*/
public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
}
二者区别为删除失败后removeLast()
将抛出异常,而pollLast()
将会返回null
删除指定元素remove(Object o)
public boolean remove(Object o) {
//如果删除对象为null
if (o == null) {
//从头开始遍历
for (Node<E> x = first; x != null; x = x.next) {
//找到元素
if (x.item == null) {
//从链表中移除找到的元素
unlink(x);
return true;
}
}
} else {
//从头开始遍历
for (Node<E> x = first; x != null; x = x.next) {
//找到元素
if (o.equals(x.item)) {
//从链表中移除找到的元素
unlink(x);
return true;
}
}
}
return false;
}
/**
* Removes the first occurrence of the specified element from this list,
* if it is present. If this list does not contain the element, it is
* unchanged. More formally, removes the element with the lowest index
* {@code i} such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>
* (if such an element exists). Returns {@code true} if this list
* contained the specified element (or equivalently, if this list
* changed as a result of the call).
*
* @param o element to be removed from this list, if present
* @return {@code true} if this list contained the specified element
*/
public boolean remove(Object o) {
if (o == null) { //如果为null
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) { //找到元素,使用等号判断(调用equals会有空指针异常)
unlink(x);
return true;
}
}
} else { //不为null
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) { //找到元素,equals判断
unlink(x);
return true;
}
}
}
return false;
}
调用此方法将只会删除一个节点(遍历时匹配到的第一个节点),而不会将所有能匹配的节点都删除
查找方法
通过下标查找元素
/**
* Returns the element at the specified position in this list.
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
//检查参数合法性
checkElementIndex(index);
调用node()方法获取item
return node(index).item;
}
node(index)
寻找到下标为index的节点
/**
* Returns the (non-null) Node at the specified element index.
返回一个node,保证不为null
*/
Node<E> node(int index) {
// assert isElementIndex(index); //调用前做过校验所以断言存在index号元素
if (index < (size >> 1)) {//由于链表下标操作为线性时间,所以采用二分查找下标降低时间复杂度
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
通过元素查找下标
从头遍历:indexOf(Object o)
,
从尾遍历lastIndexOf(Object o)
依旧区分参数是否为null
,为null
使用==
判断,不为null
使用equals()
判断
/**
* Returns the index of the first occurrence of the specified element
* in this list, or -1 if this list does not contain the element.
* More formally, returns the lowest index {@code i} such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
* or -1 if there is no such index.
*
* @param o element to search for
* @return the index of the first occurrence of the specified element in
* this list, or -1 if this list does not contain the element
*/
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
/**
* Returns the index of the last occurrence of the specified element
* in this list, or -1 if this list does not contain the element.
* More formally, returns the highest index {@code i} such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
* or -1 if there is no such index.
*
* @param o element to search for
* @return the index of the last occurrence of the specified element in
* this list, or -1 if this list does not contain the element
*/
public int lastIndexOf(Object o) {
int index = size;
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (x.item == null)
return index;
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (o.equals(x.item))
return index;
}
}
return -1;
}
contains(Object o):
检查对象o是否存在于链表中
/**
* Returns {@code true} if this list contains the specified element.
* More formally, returns {@code true} if and only if this list contains
* at least one element {@code e} such that
* <tt>(o==null ? e==null : o.equals(e))</tt>.
*
* @param o element whose presence in this list is to be tested
* @return {@code true} if this list contains the specified element
*/
public boolean contains(Object o) {
return indexOf(o) != -1;
}