definition
List
In addition to the previously mentioned ArrayList
, there are LinkedList
also very common, before these two classes of time to learn, simply record their own characteristics. If we need to add a new element many times, there is little from the middle get
of the operation, then use LinkedList
, otherwise use ArrayList
. Before our study ArrayList
found that when the source code, when we add an element, if size = capacity
the time, it will be expansion, while expansion on the back affect performance, but LinkedList
there will be no problem. Let's look at the definition:
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
}
复制代码
By definition, we can see, linkedList
we inherited AbstractSequenttialList
and the realization of the List
, Deque
, Clone
, Serializable
interface. Implements List
the basic operations, and can be clone
and serialization, and ArrayList
the biggest difference is that, ArrayList
to achieve the RandomAccess
interface, and LinkedList
to achieve the Deque
double-ended queue (Double-ended queue) interface, a double-ended queue i.e. has both stacks and queues data structure properties of . Queue elements can be operated from both ends, it may be added from both ends.
Node
Implementation
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;
}
}
复制代码
It can be found, in fact, Node
the data structure is very simple, containing only three properties
- E item: Current
Node
ofvalue
- Node next: current
Node
nextNode
what is - Node prev: currently
Node
on aNode
what is
For example in terms, there is a LinkedList
, there are two elements A
and B
, then click Add A
and B
then B
that A
's next
, and A
that B
's prev
.
Constructor
LinkedList
There are two constructors
No-argument constructor
public LinkedList() {}
复制代码
Can be found, it got nothing to do, got nothing dry means that LinkedList
the two properties Node first
and Node last
are null
, that LinkedList
is empty.
There arg constructor
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
复制代码
It can be seen passing one collection
to initialize:
- First will first call
this()
to an empty argument constructor to initializeLinkedList
- Call
addAll
method (this placeindex
issize
, the default is 0)
//在 index 所在的node前添加 c 集合节点
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index); // index >=0 && index <=size
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
//保存 index 的节点为 succ,当前节点的上一个节点为 pred
Node<E> pred, succ;
//如果 index == size ,说明在尾部进行添加,即当前节点为null,当前节点的上一个节点为
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index); // 查找 index 所在的 node
pred = succ.prev;
}
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
//如果 pred 为null,则说明 LinkedList 为空,那么当前节点就为first
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
//如果succ为空,则说明是要在尾部进行添加
if (succ == null) {
last = pred;
} else {
//否则pred(即添加的最后一个节点)的下一个节点指向当前节点(index所在的节点)
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
复制代码
Add to
LinkedList
The method includes adding add
, addFirst
, addLast
, add(int index,E e)
, , add == addLast
that is to say, we can LinkedList
insert anywhere in a node, and all add
operations are ultimately call the following two methods
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++;
}
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++;
}
复制代码
It is relatively simple to achieve, and not go into details.
delete
LinkedList
Delete method includes remove
, removeFirst
, removeLast
, remove(Object obj)
, which remove == removeFirst
, by default will be the first remove
node of the first to enter. And add
similar methods, remove
methods will eventually call the two methods
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
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
复制代码
Worthy of note is that the information is set to be deleted node is null
, the purpose is to release the head node next/prev
pointer and element
the next time gc recovery of the inner class
Obtain
LinkedList
Way to get the nodes are also similar, divided into getFirst
, getLast
and get(int index)
, for getFirst
and getLast
relatively simple, only need to acquire first
or last
the value
like. Worth a visit is the get(int index)
most important way
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;
}
}
复制代码
See this key if (index < (size >> 1))
, if you want to locate index
in the size
second half of the current length, then find from back to front, front to back or forward, in order to improve efficiency. See, if we need a lot of seek operations, in particular through index
to find, it is recommended to use ArrayList
instead LinkedList
.