java8之LinkedList集合源碼解析

// 當前鏈表的元素個數
transient int size = 0;
// 鏈表的頭部
transient Node<E> first;
// 鏈表的尾部
transient Node<E> last;

構造方法解析:

// 這種是創建一個空的鏈表
    public LinkedList() {

    }

// 使用已有的集合創建鏈表
    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);//添加集合中所有元素到鏈表中
    }


// List接口中的添加操作 :可以將元素放在頭尾部;也可以添加到制定的索引處;也可以添加整個集合;    
// add(E e)用於將元素添加到鏈表尾部,實現如下:

    public boolean add(E e) {
        linkLast(e);
        return true;
    }

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

add(int index,E e)用於在指定位置添加元素。實現如下:

    public void add(int index, E element) {
        checkPositionIndex(index); //檢索索引是否處於[0-size]之間

        if (index == size)//如果相等,則添加在鏈表尾部
            linkLast(element);
        else   //添加在鏈表中間
            linkBefore(element, node(index));
    }

在看linkBefore之前,先看一下node(int index)方法,該方法返回指定位置的節點,實現如下:

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

linkBefore()方法的解析: 

void linkBefore(E e, Node<E> succ) {

        // 創建newNode節點,將newNode的後繼指針指向succ,前驅指針指向pred 
        final Node<E> pred = succ.prev;   
        final Node<E> newNode = new Node<>(pred, e, succ);
        
        // 將succ的前驅指針指向newNode
        succ.prev = newNode;
        
        //根據pred是否爲null,進行不同操作。
        // 如果爲null,說明該節點插在頭節點前面
        if (pred == null)
            first = newNode;
        else
        // 否則直接將pred的後繼指針指向newNode即可
            pred.next = newNode;
        size++;
        modCount++;
    }

 

addAll方法解析:1. 檢查index索引範圍 2. 得到集合數據 3. 得到插入位置的前驅和後繼節點 4. 遍歷數據,將數據插入到指定位置

// 將集合從指定位置開始插入
public boolean addAll(int index, Collection<? extends E> c) {
        // 檢查index範圍
        checkPositionIndex(index);

        // 得到傳入集合的數據
        Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew == 0)
            return false;

        // 得到插入位置的前驅節點和後繼節點
        Node<E> pred, succ;

        // 如果插入位置爲尾部,前驅節點爲last,後繼節點爲null
        if (index == size) {
            succ = null;
            pred = last;
        }

        // 否則,調用node()方法得到後繼節點,再得到前驅節點
        else {
            succ = node(index);
            pred = succ.prev;
        }

        // 遍歷數據將數據插入
        for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            //創建新節點
            Node<E> newNode = new Node<>(pred, e, null);
            //如果爲空,則插入位置在鏈表頭部
            if (pred == null)
                first = newNode;
            else
             //  否則,在尾部添加
                pred.next = newNode;
                pred = newNode;
        }

        // 如果插入位置在尾部,重置last節點
        if (succ == null) {
            last = pred;
        }
        // 否則,將插入的鏈表與先前鏈表連接起來
        else {
            pred.next = succ;
            succ.prev = pred;
        }

        size += numNew;
        modCount++;
        return true;
    }   

 Deque接口的添加操作

addFirst(E e)方法

 public void addFirst(E e) {
        linkFirst(e);
    }

private void linkFirst(E e) {
        final Node<E> f = first;
        // 新建節點,以頭節點爲後繼節點
        final Node<E> newNode = new Node<>(null, e, f);
        first = newNode;
        // 如果鏈表爲空,last節點也指向該節點
        if (f == null)
            last = newNode;
        // 否則,將頭節點的前驅指針指向新節點
        else
            f.prev = newNode;
        size++;
        modCount++;
    }

總結:

   - 將數據插入到鏈表尾部 
   - boolean add(E e): 
   - void addLast(E e) 
   - boolean offerLast(E e) 


   - 將數據插入到鏈表頭部 
   - void addFirst(E e) 
   - boolean offerFirst(E e) 


   - 將數據插入到指定索引位置 
   - boolean add(int index,E e)
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章