Collection source code analysis: the underlying implementation principle of LinkedList

jdk7.0 source code analysis LinkedList underlying implementation principle


1. Overview of LinkedList

LinkedList is the implementation class of the List interface. The bottom layer is implemented with a doubly linked list, which is ordered, has subscripts, and elements can be repeated; it is not thread-safe because the underlying methods are asynchronous.

Second, the storage structure of LinkedList

The bottom layer is implemented through a doubly linked list. Each node of the linked list is a Node. In addition to its own data field, there is also a pre-pointer (prev) and a back-pointer (next), which point to the predecessor node and the subsequent node (null if not ). At the same time, the doubly linked list also has a first pointer pointing to the head node, and a last pointer pointing to the tail node. The implementation structure is as follows:

[External link image transfer failed. The source site may have an anti-hotlinking mechanism. It is recommended to save the image and upload it directly (img-JPueku8h-1586449403207) (C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\ 1572943652483.png)]

Three, LinkedList internal implementation principle mechanism (source code analysis)

  1. The basic elements of LinkedList

    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;
    
  2. Node node structure:

    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;
        }
    }
    
  3. The construction method in LinkedList:

    // 无参数的构造方法 
    public LinkedList() {
          
           }
    
    /* 将Collection类型的集合作为参数构建LinkedList
       同时将Collection集合中的所有元素存储在构建的
       LinkedList集合中,调用addAll方法
    */
    public LinkedList(Collection<? extends E> c) {
          
          
        this();
        addAll(c);
    }
    
  4. Added in LinkedList: implementation of add method

    For the linked list data structure, the operation of adding an element to the linked list structure is nothing more than adding an element at the head of the table or adding an element at the end, or adding it at a specified position. Since LinkedList has a head pointer and a tail pointer, it is more efficient when adding at the head and tail of the linked list, but if it is added at the specified position, the linked list needs to be traversed first, so the relative efficiency is low.

    a. Add elements to the header: addFirst(E e)

    [External link image transfer failed. The source site may have an anti-hotlink mechanism. It is recommended to save the image and upload it directly (img-b2xkwgEO-1586449403209) (C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\ 1572946188957.png)]

    [External link image transfer failed. The source site may have an anti-hotlinking mechanism. It is recommended to save the image and upload it directly (img-YQprWfJT-1586449403211)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\ 1572946299455.png)]

    // 在链表头部添加元素
    public void addFirst(E e) {
          
          
        linkFirst(e);
    }
    private void linkFirst(E e) {
          
          
        // f 指向头节点
        final Node<E> f = first;
        /* 新建 一个节点,以前一个节点为null
           e为节点的数据,f作为新节点的下一个节点
        */
        final Node<E> newNode = new Node<>(null, e, f);
        // 头指针指向新节点
        first = newNode;
        // 如果头指针为null,代表创建的是第一个节点
        if (f == null)
            //如果新创建为第一个结点 , 尾指针指向新节点
            last = newNode;
        else
            //如果新建的不是第一个节点,则原有头结点的前一个为 新建节点
            f.prev = newNode;
        size++; // 元素个数加1
        modCount++; // 对集合操作的次数加1
    }
    

    b. Add elements at the end of the table: addLast(E e)

    [External link image transfer failed. The source site may have an anti-hotlinking mechanism. It is recommended to save the image and upload it directly (img-CXI80y7G-1586449403212)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\ 1572946936519.png)]

    [External link image transfer failed. The source site may have an anti-hotlink mechanism. It is recommended to save the image and upload it directly (img-BxkDvoib-1586449403213)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\ 1572947000850.png)]

    // 在链表尾部添加元素
    public void addLast(E e) {
          
          
        linkLast(e);
    }
    void linkLast(E e) {
          
          
        // l 指向尾节点 
        final Node<E> l = last;
        /*新建一个节点:以原有的尾节点作为新节点的头节点
          e为新节点的存储元素,null为新节点的下一个节点
        */
        final Node<E> newNode = new Node<>(l, e, null);
        //尾节点 指向新建节点 
        last = newNode;
        // 判断新创建的节点是否为 第一个节点
        if (l == null)
            //如果新创建的节点为第一个节点,则头节点指向新节点
            first = newNode;
        else
            // 如果新建的节点不是第一个节点,则原有尾节点的下一个节点为新节点
            l.next = newNode;
        size++;
        modCount++;
    }
    

    c. Store the element at the specified location: list.add(int index, E element)

    [External link image transfer failed. The source site may have an anti-hotlinking mechanism. It is recommended to save the image and upload it directly (img-Z6ZDW4PW-1586449403215) (C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\ 1573021668030.png)]

    //将元素存储在指定下标位置上
    public void add(int index, E element) {
          
          
        // 检测指定下标是否在 0~size之间
        checkPositionIndex(index);
    	//如果指定下标为size,代表存储在尾部
        if (index == size)
            linkLast(element);
        else
            //插入到指定下标位置上 
            linkBefore(element, node(index));
    }
    //根据下标获取对应位置的节点
    Node<E> node(int index) {
          
          
        /*
        	采用的二分法查找的思想,如果下标 <长度的一半,
            则从0下标进行遍历查找(从往后查找),
            否则从往前进行查找,将查找的节点作为返回值返回
        */
    
        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;
        }
    }
    void linkBefore(E e, Node<E> succ) {
          
          
        // 获取下标对应的 前节点
        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的下一个节点
               备注:pred 代表下标对应节点的前一个节点
            */
            pred.next = newNode;
        size++;
        modCount++;
    }
    

    d. Adding method: add(E e)

    // 往LinkedList中添加元素,默认往链表的尾部添加
    public boolean add(E e) {
          
          
        linkLast(e);
        return true;
    }
    
  5. Delete method in LinkedList: remove

    [External link image transfer failed. The source site may have an anti-hotlink mechanism. It is recommended to save the image and upload it directly (img-ajw3CI6q-1586449403216) (C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\ 1573183023294.png)]

    //根据指定的下标删除对应的元素
    public E remove(int index) {
          
          
        // 检测下标是否在: 0 ~ size-1
        checkElementIndex(index);
        // 调用node方法获取下标对应的节点,并调用unlink方法删除
        return unlink(node(index));
    }
    // 删除节点
    E unlink(Node<E> x) {
          
          
        //获取被删除节点的元素,最后作为返回值返回
        final E element = x.item;
        //记录被删除节点的下一个节点
        final Node<E> next = x.next;
        //记录被删除出节点的上一个节点
        final Node<E> prev = x.prev;
    	//如果前一个节点为null,代表被删除的节点为头结点
        if (prev == null) {
          
          
            //头指针指向 被删除节点的下一个节点
            first = next;
        } else {
          
          
            /*
               如果删除的不是头结点,则被删除的节点的前一个
               节点的 next 指向被删除节点的下一个节点
            */
            prev.next = next;
            // 被删除节点的前节点置 null
            x.prev = null;
        }
    	// 如果删除的为为节点
        if (next == null) {
          
          
            // 尾指针指向被删除节点的前一个节点
            last = prev;
        } else {
          
          
            /* 如果被删除的节点不是尾节点,则被删除节点的前一个
               的next指向 而被删除节点的 下一个节点
            */
            next.prev = prev;
            //被删除节点的下一个节点置null
            x.next = null;
        }
     	// 被删除节点的元素置 null
        x.item = null;
        // 元素个数 减 1
        size--;
        modCount++;//对集合元素的改变次数加1
        return element;// 被删除的元素作为返回值返回
    }
    
  6. Query method in LinkedList: get(int index)

    //根据下标获取对应节点元素
    public E get(int index) {
          
          
        // 检测下标的有效性
        checkElementIndex(index);
        // 获取下标对应的节点
        return node(index).item;
    }
    // 获取下标对应 的节点(前面介绍过)
    Node<E> node(int 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;
        }
    }
    

Four, summary

The bottom layer of LinkedList is implemented with a doubly linked list, which has a head pointer and a tail pointer, and can quickly operate on the head node and the tail node. Compared with the array, the linked list is more efficient in adding and deleting, but the query efficiency is lower.

Guess you like

Origin blog.csdn.net/Java_lover_zpark/article/details/105424289