LinkedList_a-bit Classroom for Java Collection Source Analysis (Multi-shore College)

Posted by mediabox on Tue, 10 Sep 2019 07:49:51 +0200

After analyzing List and Queue, we can finally see the implementation of LinkedList. LinkedList compensates for the slow addition and deletion of ArrayList, but it is inferior to ArrayList in search, so it needs to be flexibly selected according to the scenario. For these two frequently used collection classes, mastering their source code and using it correctly can make our code more efficient.

LinkedList implements both List and Deque, which enables it to be used as an ArrayList, and the latter enables it to assume queue responsibilities. The internal structure of LinkedList is a two-way linked list. When we analyze Array Deque, we mentioned the concept of extending the pointer field of a single linked list and adding a pointer previous to the previous element.

AbstractSequentialList

AbstractSequential List is the parent of LinkedList. It inherits from AbstractList and is an abstract class. It mainly provides a skeleton for chain implementation of sequential list:

This class provides a skeletal implementation of the List interface to minimize the effort required to implement this interface backed by a "sequential access" data store (such as a linked list). For random access data (such as an array), AbstractList should be used in preference to this class.

This means that its main function is to provide a framework for implementing the List interface to reduce the amount of work we need to implement the implementation classes based on chain storage. AbstractSequential List does not do many special things, the most important of which is to provide a default implementation of a method and abstract the following methods in order to achieve a more scenario-compliant implementation:

public abstract ListIterator<E> listIterator(int index);

Other implementations of these methods take advantage of this listIterator method, and we will not look at it one by one. Now let's analyze the implementation of LinkedList

Structure of LinkedList

The inheritance structure of LinkedList is as follows:

We can see that LinkedList also implements Cloneable, java.io.Serializable and other methods. Drawing on the experience of ArrayList, we can think that its Clone is also a shallow clone. The serialization method also uses the same way, so we will not repeat it.

Constructing Method and Membership Variables

Data Unit Node

In introducing the structure of linked list, it is mentioned that the data units are divided into data domain and pointer domain, which store data and point to the location of the next element respectively. It can be solved by defining an entity class in java.

private static class Node<E> {
    E item; //data
    Node<E> next; //Next element
    Node<E> prev; //Last element

    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

Membership variables

LinkedList member variables have three main variables, and their meanings are clear.

// Record the length of the current linked list
transient int size = 0;

// First node
transient Node<E> first;

// Last node
transient Node<E> last;

Constructor

Because the linked list has no length problem, so it will not involve expansion and other issues, and its constructor is very concise.

public LinkedList() {
}

public LinkedList(Collection<? extends E> c) {
    this();
    addAll(c);
}

A default constructor, which does nothing, initializes with other collections and calls the addAll method. The addAll method is no longer analyzed, it should be consistent with the method of adding an element.

Important methods

LinkedList inherits both List and Deque, so it must have a bunch of methods such as add, remove, add First, add Last. These methods have similar meanings and implementations, so LinkedList extracts new methods to simplify these problems. Let's look at these non-exogenous methods and how they correspond to the above functions.

//Link an element to the top
private void linkFirst(E e) {
    //Save the original list first
    final Node<E> f = first;
    //Define a new node whose next point is to the original first
    final Node<E> newNode = new Node<>(null, e, f);
    //Point first to a new node
    first = newNode;
    //The original list is empty
    if (f == null)
        //Point last to the new node, and now both first and last point to it.
        last = newNode;
    else
        //Mount the original list after the new node, which is now first
        f.prev = newNode;
    size++;
    modCount++;
}

//Similar to linkFirst
void linkLast(E e) {
    //...
}

 //Add elements before a non-empty node
void linkBefore(E e, Node<E> succ) {
    // assert succ != null;
    //First, save the pre-nodes of succ node
    final Node<E> pred = succ.prev;
    //The new node is interpolated between pred and succ
    final Node<E> newNode = new Node<>(pred, e, succ);
    //The prev pointer of succ moves to the new node
    succ.prev = newNode;
    //The leading node is empty
    if (pred == null)
        //The instructions are inserted in the first place
        first = newNode;
    else
        //Pointer the next pointer of the preceding node to the new node
        pred.next = newNode;
    size++;
    modCount++;
}

//Delete the primary element, which must be non-empty
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) {
    //...
}

//Delete a specified node
E unlink(Node<E> x) {
    //...
}

As you can see, LinkedList provides a series of methods for insertion and deletion, but it does not implement another method for query, because the query of linked list is relatively slow, so it is implemented through another method. Let's see:

public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}

//I can say I did my best.
Node<E> node(int index) {
    // assert isElementIndex(index);
    
    //Size > 1 means to take half.
    //Halve the number of Traversals
    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;
    }
}

Finally, let's see how it corresponds to those inherited methods:

//Referring to the node method, you need to traverse
public E set(int index, E element) {
    checkElementIndex(index);
    Node<E> x = node(index);
    E oldVal = x.item;
    x.item = element;
    return oldVal;
}

//It may also require traversal
public void add(int index, E element) {
    checkPositionIndex(index);

    if (index == size)
            linkLast(element);
    else
        linkBefore(element, node(index));
}

//Also traverse
public E remove(int index) {
    checkElementIndex(index);
    return unlink(node(index));
}

public E peek() {
    final Node<E> f = first;
    return (f == null) ? null : f.item;
}

public E element() {
    return getFirst();
}

public E poll() {
    final Node<E> f = first;
    return (f == null) ? null : unlinkFirst(f);
}

public E remove() {
    return removeFirst();
}

public boolean offer(E e) {
    return add(e);
}

public boolean offerFirst(E e) {
    addFirst(e);
    return true;
}

//...

summary

LinkedList is very suitable for inserting and deleting large amounts of data, but it needs half-traversal for elements in the middle, whether adding or deleting or revising, which will greatly affect the performance when the amount of data is large. When using it, try not to involve queries and inserting data in the middle. In addition, if you want to traverse, you'd better use foreach, which is the way Iterator provides.

Thank you for seeing it. If you can help me, please give me a compliment.

More experience and technology are welcome to come and learn together. A Little Classroom - Online Learning Platform for Dreams http://www.yidiankt.com/

[Pay attention to the public number and reply to "1" for free - [java Core Knowledge Points]

QQ discussion group: 616683098

QQ: 3184402434

Students who want to study in depth can study and discuss with QQ ~and have a full set of resources to share, experience to explore, wait for you!

Topics: Programming Java