上一篇文章我们分析了ArrayList的基本内容,这一篇再来看一下LinkedList,因为在使用列表的时候除了使用ArrayList,有时也会用LinkedList。接下来就通过源码来分析一下LinkedList:
LinkedList是 List和Deque接口的双链表实现。实现所有可选的列表操作,并允许所有元素(包括null)。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
……
}
LinkedList继承了AbstractSequentialList,实现的接口有List、Deque、Cloneable(可被克隆)、Serializable(支持序列化)
接口Deque实现了一个双端队列 :既可以添加到队尾,也可以添加到队首;既可以从队首获取,又可以从队尾获取。
1)初始化:创建一个空列表,声明的时候不需要指定大小,元素增加或者删除时大小随之改变。
LinkedList<Object> linkedList = new LinkedList<>();
/**
* Constructs an empty list.
*/
public LinkedList() {
}
2)add(E e)方法:将指定元素追加到此列表的末尾。与addLast(E e)方法作用相同,时间复杂度为O(1)。
/**
* 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;
}
/**
* 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);
}
/**
* 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++;
}
3)add(int index, E element)方法:将指定元素插入到此列表中的指定位置。将当前位于该位置的元素(如果有的话)和所有后续元素向右移动(向它们的索引添加1)。
/**
* 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);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
首先通过checkPositionIndex(index);来检查要插入指定元素的索引是否有效,如果有效则继续运行,若无效则会抛出异常;
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/**
* Tells if the argument is the index of a valid position for an
* iterator or an add operation.
*/
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
如果要插入的索引是列表的大小,则将该元素追加到列表的末尾,同1)中的add(E e)方法或addLast(E e)方法,此时的时间复杂度是O(1);否则 会在非空节点之前插入该元素,这是会先通过node(int index)方法遍历查找指定元素索引处的非空节点,此时的时间复杂度是O(n)。
/**
* Inserts element e before non-null Node succ.
*/
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
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++;
}
/**
* Returns the (non-null) Node at the specified element index.
*/
Node<E> node(int index) {
// assert isElementIndex(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;
}
}
通过源码可以看到node(int index)方法遍历查找指定元素索引处的非空节点的时候是分成两部分来遍历查找的,当要查的元素的index索引小于列表大小的一半时候,进行index之前的部分查找;当要查的元素的index索引大于列表大小的一半时候,进行index之后的部分查找,这样可以节省很多时间,那么是否可以看成此时的时间复杂度为O(n/2)呢。
4)addFirst(E e)方法:将指定的元素插入到列表的开头,此时的时间复杂度是O(1)。
/**
* Inserts the specified element at the beginning of this list.
*
* @param e the element to add
*/
public void addFirst(E 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++;
}
5)get(int index)方法:返回此列表中指定位置的元素。因为用到了node(int index)方法,循环遍历链表,因此时间复杂度为O(n)。
/**
* 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);
return node(index).item;
}
6)getFirst()方法:返回此列表中的第一个元素,时间复杂度是O(1)。
/**
* Returns the first element in this list.
*
* @return the first element in this list
* @throws NoSuchElementException if this list is empty
*/
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
7)getLast()方法:返回此列表中的最后一个元素,时间复杂度是O(1)。
/**
* Returns the last element in this list.
*
* @return the last element in this list
* @throws NoSuchElementException if this list is empty
*/
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
8)remove(int index)方法:移除此列表中指定位置的元素。将所有后续元素向左移动(从它们的索引中减去1)。返回从列表中删除的元素。因为用到了node(int index)方法,循环遍历链表,因此时间复杂度为O(n)。
/**
* Removes the element at the specified position in this list. Shifts any
* subsequent elements to the left (subtracts one from their indices).
* Returns the element that was removed from the list.
*
* @param index the index of the element to be removed
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
/**
* Unlinks non-null node x.
*/
E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
9)remove()方法,与removeFirst()方法作用相同:从此列表中删除并返回第一个元素,时间复杂度是O(1)。
public E remove() {
return removeFirst();
}
/**
* Removes and returns the first element from this list.
*
* @return the first element from this list
* @throws NoSuchElementException if this list is empty
*/
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
10)removeLast()方法:从此列表中删除并返回最后一个元素,时间复杂度是O(1)。
/**
* 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);
}
11)contains(Object o)方法:遍历查找列表中是否包含指定元素(可为null),时间复杂度为O(n)。
public boolean contains(Object o) {
return indexOf(o) != -1;
}
/**
* 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;
}
12)clear()方法:从此列表中删除所有元素。此调用返回后,列表将为空。时间复杂度为O(n)。
/**
* Removes all of the elements from this list.
* The list will be empty after this call returns.
*/
public void clear() {
// Clearing all of the links between nodes is "unnecessary", but:
// - helps a generational GC if the discarded nodes inhabit
// more than one generation
// - is sure to free memory even if there is a reachable Iterator
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}
以上这些方法汇总
LinkedList<Object> linkedList = new LinkedList<>();
linkedList.add("1");
linkedList.add(1,"");
linkedList.addFirst("");
linkedList.addLast("");
linkedList.get(0);
linkedList.getFirst();
linkedList.getLast();
linkedList.remove(0);
linkedList.remove();
linkedList.removeFirst();
linkedList.removeLast();
linkedList.contains("");
linkedList.clear();
下一篇再分析一下下面的一些方法
linkedList.offer("");//add(e)、addLast(e)
linkedList.offerFirst("");//addFirst(e)
linkedList.offerLast("");//addLast(e)
linkedList.peek();//peekFirst
linkedList.peekFirst();
linkedList.peekLast();
linkedList.poll();//pollFirst
linkedList.pollFirst();
linkedList.pollLast();
linkedList.pop();//removeFirst()
linkedList.push("");//addFirst(e)
linkedList.set(0,"");