Properties of class
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable { // Number of actual elements transient int size = 0; // Pointer to the head node transient Node<E> first; // Pointer to tail node transient Node<E> last; }
Constructor
LinkedList() type constructor
public LinkedList() { }
LinkedList (collection <? Extensions E >) type constructor
public LinkedList(Collection<? extends E> c) { // Call parameterless constructor this(); // Add all elements in the collection addAll(c); }
Core function analysis
Add (e e e) function
public boolean add(E e) { // Add to end linkLast(e); return true; }
linklast(E e) function analysis the actual call of addLast function
void linkLast(E e) { // Remember tail pointer final Node<E> l = last; // The prev of the new node is l, the successor is null, and the value is e final Node<E> newNode = new Node<>(l, e, null); // Update tail pointer last = newNode; if (l == null) // If the list is empty first = newNode; // Head pointer equals tail pointer else // Tail node is not empty l.next = newNode; // The successor of the tail node is the newly generated node // Size plus 1 size++; // Structural modification plus 1 modCount++; }
The actual call of linkfirst (e e e) function addFirst function
private void linkFirst(E e) { //Remember the head node final Node<E> f = first; //Instantiate new node, prev = null,last = first final Node<E> newNode = new Node<>(null, e, f); //Head pointer to new node first = newNode; if (f == null) //If the head pointer is null, the tail pointer also points to the new node last = newNode; else f.prev = newNode; size++; modCount++; }
add(int index,E element) function
public void add(int index, E element) { checkPositionIndex(index); if (index == size) linkLast(element); else linkBefore(element, node(index)); }
linkBefore(E e,Node succ)
void linkBefore(E e, Node<E> succ) { // Remember the forerunner final Node<E> pred = succ.prev; //Instantiate a new node, initialize the forerunner and the successor final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode; if (pred == null) //If it is a header insert, modify the header pointer to point to the new node first = newNode; else pred.next = newNode; size++; modCount++; }
Addall (int index, collection <? Extends E > C) function
// Add a collection public boolean addAll(int index, Collection<? extends E> c) { // Check whether the inserted position is legal checkPositionIndex(index); // Convert collection to array Object[] a = c.toArray(); // Save collection size int numNew = a.length; if (numNew == 0) // Set is empty, return directly return false; Node<E> pred, succ; // Attention is the entry precursor and successor of the whole set if (index == size) { // If the insertion position is at the end of the list, the successor is null and the predecessor is the tail node succ = null; pred = last; } else { // Insert at some other location succ = ode(index); n// Find the node pred = succ.prev; // Save the precursor of this node } for (Object o : a) { // Traversal array E e = (E) o; // Downward transformation // Generate new node Node<E> newNode = new Node<>(pred, e, null); if (pred == null) // Indicates to insert before the first element (node with index 0) first = newNode; else pred.next = newNode; pred = newNode; } if (succ == null) { // Indicates insert after last element last = pred; } else { pred.next = succ; succ.prev = pred; } // Modify the number of actual elements size += numNew; // Structural modification plus 1 modCount++; return true; }
node(int index) function
Node<E> node(int index) { // Judge whether the insertion position is in the first half or the second half of the list if (index < (size >> 1)) { // Insertion position in the first half Node<E> x = first; for (int i = 0; i < index; i++) // Forward traversal from the beginning of the node x = x.next; return x; // Return to this node } else { // Insert in the second half Node<E> x = last; for (int i = size - 1; i > index; i--) // Reverse traversal from tail node x = x.prev; return x; // Return to this node } }
Why not divide it into three segments? The index node of the linked list depends on the first and last pointers. Even if it is divided into more segments and the location is accurate, it should start from the first or last
remove(Object o) function
public boolean remove(Object o) { if (o == null) { //It also indicates that LinkedList allows null insertion 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; }
unlink(Node x) function
E unlink(Node<E> x) { //Returns the node value of x final E element = x.item; //Remember the forerunner final Node<E> next = x.next; //Remember to follow final Node<E> prev = x.prev; //If the deleted node is a header node, the header pointer points to next if (prev == null) { first = next; } else { prev.next = next; x.prev = null; } //If the deleted node is a tail node, the tail pointer points to prev if (next == null) { last = prev; } else { next.prev = prev; x.next = null; } //Collection content null x.item = null; size--; modCount++; return element; }
unlinkFirst(Node f) function actual call to removeFirst function
private E unlinkFirst(Node<E> f) { // Remember node values and successors final E element = f.item; final Node<E> next = f.next; f.item = null; f.next = null; // help GC //Head pointer to follow first = next; if (next == null) //If the link list is empty after deleting a node, the tail pointer points to null last = null; else next.prev = null; size--; modCount++; return element; }
The actual call to unlinkLast(Node l) removeLast function
private E unlinkLast(Node<E> l) { // Remember node values and precursors final E element = l.item; final Node<E> prev = l.prev; l.item = null; l.prev = null; // help GC //Tail node points to precursor last = prev; if (prev == null) //If the link list is empty after deleting a node, the head pointer points to null first = null; else prev.next = null; size--; modCount++; return element; }