"OpenJdk-11 source - Series" LinkedList

definition

ListIn addition to the previously mentioned ArrayList, there are LinkedListalso 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 getof the operation, then use LinkedList, otherwise use ArrayList. Before our study ArrayListfound that when the source code, when we add an element, if size = capacitythe time, it will be expansion, while expansion on the back affect performance, but LinkedListthere 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, linkedListwe inherited AbstractSequenttialListand the realization of the List, Deque, Clone, Serializableinterface. Implements Listthe basic operations, and can be cloneand serialization, and ArrayListthe biggest difference is that, ArrayListto achieve the RandomAccessinterface, and LinkedListto achieve the Dequedouble-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.

NodeImplementation

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, Nodethe data structure is very simple, containing only three properties

  • E item: Current Nodeofvalue
  • Node next: current Nodenext Nodewhat is
  • Node prev: currently Nodeon a Nodewhat is

For example in terms, there is a LinkedList, there are two elements Aand B, then click Add Aand Bthen Bthat A's next, and Athat B's prev.

Constructor

LinkedListThere are two constructors

No-argument constructor

public LinkedList() {}
复制代码

Can be found, it got nothing to do, got nothing dry means that LinkedListthe two properties Node firstand Node lastare null, that LinkedListis empty.

There arg constructor

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

It can be seen passing one collectionto initialize:

  1. First will first call this()to an empty argument constructor to initializeLinkedList
  2. Call addAllmethod (this place indexis size, 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

LinkedListThe method includes adding add, addFirst, addLast, add(int index,E e), , add == addLastthat is to say, we can LinkedListinsert anywhere in a node, and all addoperations 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

LinkedListDelete method includes remove, removeFirst, removeLast, remove(Object obj), which remove == removeFirst, by default will be the first removenode of the first to enter. And addsimilar methods, removemethods 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/prevpointer and elementthe next time gc recovery of the inner class

Obtain

LinkedListWay to get the nodes are also similar, divided into getFirst, getLastand get(int index), for getFirstand getLastrelatively simple, only need to acquire firstor lastthe valuelike. 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 indexin the sizesecond 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 indexto find, it is recommended to use ArrayListinstead LinkedList.

Guess you like

Origin juejin.im/post/5d7bbed9f265da03951a227a