jdk source code - > collection - > LinkedList

Keywords: Java

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;
    }

Posted by Ozzapoo on Thu, 30 Apr 2020 02:40:19 -0700