Java集合(四) LinkedList詳解

  在上篇文章Java集合(三) ArrayList詳解的學習和源碼分析中,咱們知道ArrayList是以數組實現,它的優點是查詢性能高,劣勢是按順序增刪性能差。若是在不肯定元素數量的狀況時,不建議使用ArrayList。其實當這種狀況時,咱們就可使用LinkedList了。java

大O記號

  一直以來咱們用快慢來描述存儲算法,這種直觀的描述是很差的。有一種方法能夠量化一種操做的耗時狀況。咱們能夠借用數學分析中的大O記號來描述這種關係。
  解決一個規模爲n的問題所花費的步驟若是是n的常數倍,咱們就記這個方法的複雜度爲O(n)。例如,給一個數組,求這個數組中的最大值,須要遍歷這個數組,若是數組長度爲n,那麼遍歷數組的步驟就是n。因此,這是一種O(n)的操做。一樣,解決一個規模爲n的問題所花費的步驟若是是n^2的常數倍,咱們就記這個方法的複雜度爲O(n^2)。好比冒泡排序。而解決問題的步驟若是與問題規模無關,這個時間複雜度就是O(1)的。好比,數組的隨機存取。而數組的順序存儲就是O(n)的。node

鏈表

  在學習LinkedList以前,咱們先對數據結構中鏈表作一個簡單的回顧。鏈表是一種物理存儲單元上非連續、非順序的存儲結構,數據元素的邏輯順序是經過鏈表中的指針連接次序實現的。鏈表由一系列結點(鏈表中每個元素成爲結點)組成,結點能夠在運行時動態生成。
能夠這樣理解:
  有一條街,小明住在街中一角,他有小紅的地址,而後小紅也是住在這條街,他有小花的地址,一樣小花也有別人的地址。某天我想找小紅玩,可是我不知道她住在哪裏,我能夠問小明,就知道小紅住在哪裏了。那麼小明小紅小花這些人之間的關係就組成一個鏈表。 git

  • 單鏈表:就是小明只是右手握着小紅的地址,他只有小紅一我的的地址
  • 雙鏈表:就是小紅左手握着小明的地址,右手握着小花的地址,她有兩我的的地址
  • 循環鏈表:就是小明握着小紅的地址,小紅握着小花的地址,而小花又握着小明的地址,這樣就造成了一個循環
  • 有序鏈表:以某個標準,給鏈表的元素排序,好比比較內容大小、比較哈希值等 若是還很差理解,咱們能夠先看一個類的定義:
public class LinkNode {
    public int data;
    public LinkNode next;

    public LinkNode(int data) {
        this.data = data;
        this.next = null;
    }
}
複製代碼

咱們定義了一個LinkNode類,這個類有兩個成員變量,一個是整形data,還有一個是指向LinkNode類型的引用。經過這個引用,就能夠把多個LinkNode串起來,好比,下面的代碼:github

LinkNode head = new LinkNode(1);
        head.next = new LinkNode(2);
複製代碼

這樣就在內存裏建立了兩個LinkNode對象,它們之間的關係就像這樣: 算法

head所引用的那個LinkNode,其data爲1,其next指向下一個LinkNode,其data爲2,next域爲空。

鏈表增長一項

  若是我想在head以後,增長一個鏈表項,讓這個鏈表變成下圖的樣子,該怎麼作? 數組

  思路就是先把新的結點的next設爲head的next,而後再使得head.next指向新的結點便可。

LinkNode newNode = new LinkNode(3);
        newNode.next = head.next;
        head.next = newNode;
複製代碼

  反過來,想要把head後面的那個結點刪掉,也很簡單,只須要讓head的next再日後指一項,把原來head後面的那一項跳過去就能夠了:安全

head.next = head.next.next;
複製代碼

  能夠看到,在鏈表中,指定的結點後面添加一個項是常數時間的,也就是O(1),刪除一個項也是同樣的。但與數組不一樣的,若是我要完成「查詢鏈表中的第n項是什麼」這個操做,就會變成O(n)的,由於咱們每次查找都必須從頭開始,依次向後查找。bash

public static int queryData(LinkNode head, int index) {
        LinkNode cur = head;
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }

        return cur.data;
    }
複製代碼

  再看一個問題,假如我知道了一個LinkNode,不妨記爲temp,位於一個鏈表中,若是想知道這個結點的上一個結點是什麼,應該怎麼辦?對於咱們前邊定義的鏈表結構,只能從頭開始找,去判斷是否有某個結點,它的next與temp相等。若是相等就說明,這個結點就是temp的前序結點。代碼以下:數據結構

public static LinkNode findPrevious(LinkNode head, LinkNode temp) {
        LinkNode cur = head;
        while (cur != null) {
            if (cur.next == temp)
                return cur;

            cur = cur.next;
        }

        return null;
    }
複製代碼

雙向鏈表

  實際上,在工程實踐中,使用鏈表的時候,常常會有「查詢某個結點的前一結點」這樣的需求,爲了加速這一過程,咱們其實能夠修改一下LinkNode的定義,結它加上一個指向前序結點的成員變量:ide

public class DoubleLinkNode {
    public int data;
    public LinkNode next;
    public LinkNode prev;

    public DoubleLinkNode(int data) {
        this.data = data;
        this.next = null;
        this.prev = null;
    }
}
複製代碼

這樣的話,鏈表就成了這個樣子了:

  這樣一來,查找某個結點的上一個結點,只要返回它的prev就能夠了。
  好了。鏈表的學習就到這裏了。

LinkedList

概述

  LinkedList以雙向鏈表實現。鏈表無容量限制,但雙向鏈表自己使用了更多空間,也須要額外的鏈表指針操做。除了實現List接口外,LinkedList還爲在列表的開頭及結尾get、remove和insert元素提供了統一的命名方法。這些操做能夠將連接列表看成棧,隊列和雙端隊列來使用。
  按索引訪問元素:get(i)/set(i,e)要很是噁心的遍歷鏈表將指針移動到位(若是i > 數組大小的一半,會從末尾開始移動)。插入、刪除元素時修改先後節點的指針便可,但仍是要遍歷部分鏈表的指針才能移動到下標所指的位置,只有在鏈表兩頭的操做:add(),addFirst(),removeLast()或用iterator()上的remove()能省掉指針的移動。
  LinkedList一樣是非線程安全的,只在單線程下適合使用。若是多個線程同時訪問一個連接列表,而其中至少一個線程從結構上修改了該列表,則它必須保持外部同步。(結構修改指添加或刪除一個或多個元素的任何操做;僅設置元素的值不是結構修改。)這通常經過對天然封裝該列表的對象進行同步操做來完成。若是不存在這樣的對象,則應該使用 Collections.synchronizedList 方法來「包裝」該列表。
  LinkedList的iterator和listIterator方法返回的迭代器是快速失敗的(fail-fast機制):在迭代器建立以後,若是從結構上對列表進行修改,除非經過迭代器自身的remove或add方法,其餘任什麼時候間任何方式的修改,迭代器都將拋出 ConcurrentModificationException。
  LinkedList實現了Serializable接口,所以它支持序列化,可以經過序列化傳輸,實現了Cloneable接口,能被克隆。

LinkedList源碼解析

public class LinkedList<E>
        extends AbstractSequentialList<E>
        implements List<E>, Deque<E>, Cloneable,
        java.io.Serializable {
    //LinkedList中鏈表元素個數
    transient int size = 0;
    //鏈表頭結點
    transient Node<E> first;
    //鏈表尾結點
    transient Node<E> last;

    //默認構造方法,生成一個空的鏈表
    public LinkedList() {
    }

    //根據c裏面的元素生成一個LinkedList
    public LinkedList(Collection<? extends E> c) {
        //調用空的構造方法
        this();
        //將c裏面的元素添加到空鏈表尾部
        addAll(c);
    }

    //首部增長結點,結點的值爲e
    private void linkFirst(E e) {

        final Node<E> f = first;//f指向頭結點
        //生成一個新結點,結點的值爲e,其前向指針爲null,後向指針爲f
        final Node<E> newNode = new Node<>(null, e, f);
        //first指向新生成的結點,f保存着舊的頭結點信息
        first = newNode;
        if (f == null)
            //若是f爲null,則表示整個鏈表目前是空的,則尾結點也指向新結點
            last = newNode;
        else
            //f(老的頭結點)的前向指向最新的結點信息
            f.prev = newNode;
        size++;//元素個數+1
        modCount++;//修改次數+1
    }

    //尾部增長結點,結點的值爲e
    void linkLast(E e) {
        final Node<E> l = last; //l指向尾結點
        //生成一個新結點,結點的值爲e,其前向指針爲l,後向指針爲null
        final Node<E> newNode = new Node<>(l, e, null);
        //last指向新生成的結點,l保存着舊的尾結點信息
        last = newNode;
        if (l == null)
            //若是l爲null,則表示整個鏈表目前是空的,則頭結點也指向新結點
            first = newNode;
        else
            //l(舊的尾結點)的後向指針指向最新的結點信息
            l.next = newNode;
        size++;//元素個數+1
        modCount++;//修改次數+1
    }

    //非空結點succ以前插入新結點,新結點的值爲e
    void linkBefore(E e, Node<E> succ) {
        // assert succ != null; //外界調用需保證succ不爲null,不然程序會拋出空指針異常
        final Node<E> pred = succ.prev;//pred指向succ的前向結點
        //生成一個新結點,結點的值爲e,其前向指針指向pred,後向指針指向succ
        final Node<E> newNode = new Node<>(pred, e, succ);
        succ.prev = newNode;//succ的前向指針指向newNode
        if (pred == null)
            //若是pred爲null,則表示succ爲頭結點,此時頭結點指向最新生成的結點newNode
            first = newNode;
        else
            //pred的後向指針指向新生成的結點,此時已經完成告終點的插入操做
            pred.next = newNode;
        size++;//元素個數+1
        modCount++;//修改次數+1
    }

    //刪除頭結點,並返回該結點的值
    private E unlinkFirst(Node<E> f) {
        // assert f == first && f != null;//需確保f爲頭結點,且鏈表不爲null
        final E element = f.item;//得到結點的值
        final Node<E> next = f.next;//next指向f的後向結點
        f.item = null;//釋放數據結點
        f.next = null; // help GC   //釋放f的後向指針
        first = next;   //first指向f的後向結點
        if (next == null)
            //若是next爲null,則表示f爲last結點,此時鏈表即爲空鏈表
            last = null;
        else
            //修改next的前向指針,由於first結點的前向指針爲null
            next.prev = null;
        size--; //元素個數-1
        modCount++; //修改次數+1
        return element;
    }

    //刪除尾結點,並返回尾結點的內容
    private E unlinkLast(Node<E> l) {
        // assert l == last && l != null;   //需確保l爲尾結點,且鏈表不爲null
        final E element = l.item;   //得到結點的值
        final Node<E> prev = l.prev;    //prev執行1的前向結點
        l.item = null;  //釋放l結點的值
        l.prev = null; // help GC   //釋放l結點的前向指針
        last = prev;    //last結點指向l的前向結點
        if (prev == null)
            //若是prev爲null,則表示l爲first結點,此時鏈表即爲空鏈表
            first = null;
        else
            //修改prev的後向指針,由於last結點的後向指針爲null
            prev.next = null;
        size--;//元素個數-1
        modCount++;//修改次數+1
        return element;
    }

    //刪除結點x
    E unlink(Node<E> x) {
        // assert x != null;    //需確保x不爲null,不然後續操做會拋出空指針異常
        final E element = x.item;   //保存x結點的值
        final Node<E> next = x.next;//next指向x的後向結點
        final Node<E> prev = x.prev;//prev指向x的前向結點

        if (prev == null) {
            //若是prev爲空,則x結點爲first結點,此時first結點指向next結點(x的後向結點)
            first = next;
        } else {
            prev.next = next;//x的前向結點的後向指針指向x的後向結點
            x.prev = null;  //釋放x的前向指針
        }

        if (next == null) {
            //若是next結點爲空,則x結點爲尾部結點,此時last結點指向prev結點(x的前向結點)
            last = prev;
        } else {
            next.prev = prev;//x的後向結點的前向指針指向x的前向結點
            x.next = null;  //釋放x的後向指針
        }

        x.item = null;  //釋放x的值節點,此時x節點能夠徹底被GC回收
        size--; //元素個數-1
        modCount++; //修改次數+1
        return element;
    }

    //得到頭結點的值
    public E getFirst() {
        final Node<E> f = first;//f指向first結點
        if (f == null)//若是鏈表爲空
            throw new NoSuchElementException();
        return f.item;//返回first結點的值
    }

    //得到尾結點的值
    public E getLast() {
        final Node<E> l = last; //l指向last結點
        if (l == null)//若是鏈表爲空
            throw new NoSuchElementException();
        return l.item;//返回last結點的值
    }

    //移除頭結點
    public E removeFirst() {
        final Node<E> f = first;//得到頭結點
        if (f == null)//若是鏈表爲空
            throw new NoSuchElementException();
        return unlinkFirst(f);  //摘除頭結點
    }

    //移除尾結點
    public E removeLast() {
        final Node<E> l = last;//得到尾結點
        if (l == null)//若是鏈表爲空
            throw new NoSuchElementException();
        return unlinkLast(l);//摘除尾結點
    }

    //添加到頭結點,結點的值爲e
    public void addFirst(E e) {
        linkFirst(e);//添加到頭部
    }

    //添加到尾結點
    public void addLast(E e) {
        linkLast(e);//添加到尾部
    }

    //判斷元素(值爲o)是否o在鏈表中
    public boolean contains(Object o) {
        return indexOf(o) != -1;//定位元素
    }

    //返回元素個數
    public int size() {
        return size;
    }

    //添加元素,元素值爲e
    public boolean add(E e) {
        linkLast(e);//添加到鏈表尾部
        return true;
    }

    //移除值爲o的元素,o能夠爲null,找到一個刪除即返回
    public boolean remove(Object o) {
        if (o == null) {//元素爲null
            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;
    }

    //將c中的元素都添加到當前鏈表中
    public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);//添加到鏈表尾部
    }

    //在序號爲index處,添加c中全部的元素到當前鏈表中(後向添加)
    public boolean addAll(int index, Collection<? extends E> c) {
        checkPositionIndex(index);//判斷index是否超出界

        Object[] a = c.toArray();//將集合轉換爲數組
        int numNew = a.length;
        if (numNew == 0)
            return false;

        Node<E> pred, succ;
        if (index == size) {//若是index爲元素個數,即index個結點爲尾結點
            succ = null;
            pred = last;//指向爲結點
        } else {
            succ = node(index); //succ指向第index個結點
            pred = succ.prev;   //pred指向succ的前向結點
        }

        //for循環結束後,a裏面的元素都添加到當前鏈表裏面,後向添加
        for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            //新生成一個結點,結點的前向指針指向pred,後向指針爲null
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null)
                //若是pred爲null,則succ爲當前頭結點
                first = newNode;
            else
                //pred的後向指針指向新結點
                pred.next = newNode;
            pred = newNode;//pred移動到新結點
        }

        if (succ == null) {
            last = pred;//succ爲null,這表示index爲尾結點以後
        } else {
            //pred表示全部元素添加以後的最後結點,此時pred的後向指針指向以前的記錄的結點
            pred.next = succ;
            succ.prev = pred;//以前記錄的結點指向添加元素以後的最後結點
        }

        size += numNew;//元素個數+num
        modCount++;//修改次數+1
        return true;
    }

    //清除鏈表裏面的全部元素
    public void clear() {
        for (Node<E> x = first; x != null; ) {
            Node<E> next = x.next;
            x.item = null;  //釋放值結點,便於GC回收
            x.next = null;  //釋放前向指針
            x.prev = null;  //釋放後向指針
            x = next;   //後向遍歷
        }
        first = last = null;//釋放頭尾結點
        size = 0;
        modCount++;
    }


    //得到第index個結點的值
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;    //點位第index結點,返回值信息
    }

    //設置第index元素的值
    public E set(int index, E element) {
        checkElementIndex(index);
        Node<E> x = node(index);//定位第index個結點
        E oldVal = x.item;
        x.item = element;
        return oldVal;
    }

    //第index個結點以前添加結點
    public void add(int index, E element) {
        checkPositionIndex(index);

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

    //刪除第index個結點
    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }

    //判斷index是不是鏈表中的元素的索引
    private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
    }

    //判斷index是不是鏈表中的元素的索引
    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }

    private String outOfBoundsMsg(int index) {
        return "Index: " + index + ", Size: " + size;
    }

    private void checkElementIndex(int index) {
        if (!isElementIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    //定位鏈表中的第index個結點
    Node<E> node(int index) {
        // assert isElementIndex(index);//確保是合法的索引,即0<=index<=size
        //index小於size的一半時,從頭向後找
        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {//index大於size的一半時,從尾向前找
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

    //定位元素,首次出現的元素的值爲o的結點序號
    public int indexOf(Object o) {
        int index = 0;
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null)
                    return index;
                index++;
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item))
                    return index;
                index++;
            }
        }
        return -1;
    }

    //定位元素,最後一次出現的元素值爲o的元素序號
    public int lastIndexOf(Object o) {
        int index = size;
        if (o == null) {
            for (Node<E> x = last; x != null; x = x.prev) {
                index--;
                if (x.item == null)
                    return index;
            }
        } else {
            for (Node<E> x = last; x != null; x = x.prev) {
                index--;
                if (o.equals(x.item))
                    return index;
            }
        }
        return -1;
    }

    //實現隊列操做,返回第一個元素的值
    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;
    }

    //添加尾結點
    public boolean offerLast(E e) {
        addLast(e);
        return true;
    }

    //返回頭結點的值
    public E peekFirst() {
        final Node<E> f = first;
        return (f == null) ? null : f.item;
    }

    //返回尾結點的值
    public E peekLast() {
        final Node<E> l = last;
        return (l == null) ? null : l.item;
    }

    //彈出第一個結點
    public E pollFirst() {
        final Node<E> f = first;
        return (f == null) ? null : unlinkFirst(f);
    }

    //彈出最後一個結點
    public E pollLast() {
        final Node<E> l = last;
        return (l == null) ? null : unlinkLast(l);
    }

    //添加頭部結點
    public void push(E e) {
        addFirst(e);
    }

    //彈出第一個結點
    public E pop() {
        return removeFirst();
    }

    //刪除值爲o的結點
    public boolean removeFirstOccurrence(Object o) {
        return remove(o);
    }

    //刪除值爲o的結點(從尾部遍歷)
    public boolean removeLastOccurrence(Object o) {
        if (o == null) {
            for (Node<E> x = last; x != null; x = x.prev) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = last; x != null; x = x.prev) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

    //返回雙向迭代器
    public ListIterator<E> listIterator(int index) {
        checkPositionIndex(index);
        return new ListItr(index);
    }
    //私有內部類,實現雙向迭代器
    private class ListItr implements ListIterator<E> {
        private Node<E> lastReturned;//記錄當前結點信息
        private Node<E> next;//當前結點的後向結點
        private int nextIndex;//當前結點的序號
        private int expectedModCount = modCount;//修改次數
        //初始化
        ListItr(int index) {
            // assert isPositionIndex(index);
            next = (index == size) ? null : node(index);
            nextIndex = index;
        }
        //是否有結點
        public boolean hasNext() {
            return nextIndex < size;
        }
        //返回下一個結點
        public E next() {
            checkForComodification();
            if (!hasNext())
                throw new NoSuchElementException();

            lastReturned = next;//記錄當前結點
            next = next.next;//向後移動
            nextIndex++;//結點序號+1
            return lastReturned.item;
        }
        //是否有前向結點
        public boolean hasPrevious() {
            return nextIndex > 0;
        }
        //返回前向結點
        public E previous() {
            checkForComodification();
            if (!hasPrevious())
                throw new NoSuchElementException();

            lastReturned = next = (next == null) ? last : next.prev;
            nextIndex--;
            return lastReturned.item;
        }
        //返回當前結點序號
        public int nextIndex() {
            return nextIndex;
        }
        //返回當前結點的前一個序號
        public int previousIndex() {
            return nextIndex - 1;
        }
        //刪除結點
        public void remove() {
            checkForComodification();
            if (lastReturned == null)
                throw new IllegalStateException();

            Node<E> lastNext = lastReturned.next;
            unlink(lastReturned);
            if (next == lastReturned)
                next = lastNext;
            else
                nextIndex--;
            lastReturned = null;
            expectedModCount++;
        }
        //設置當前結點的值
        public void set(E e) {
            if (lastReturned == null)
                throw new IllegalStateException();
            checkForComodification();
            lastReturned.item = e;
        }
        //當前結點前面插入新結點信息
        public void add(E e) {
            checkForComodification();
            lastReturned = null;
            if (next == null)
                linkLast(e);
            else
                linkBefore(e, next);
            nextIndex++;
            expectedModCount++;
        }
        // Lambda表達式結合迭代器進行遍歷
        public void forEachRemaining(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            while (modCount == expectedModCount && nextIndex < size) {
                action.accept(next.item);
                lastReturned = next;
                next = next.next;
                nextIndex++;
            }
            checkForComodification();
        }
        //判斷迭代期間是否被修改
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

    private static class Node<E> {
        E item; //結點的值
        Node<E> next;   //結點的後向指針
        Node<E> prev;   //結點的前向指針

        //構造方法中已完成Node成員的賦值
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;    //結點的值賦值爲element
            this.next = next;       //後向指針賦值
            this.prev = prev;       //前向指針賦值
        }
    }

    //返回前向迭代器
    public Iterator<E> descendingIterator() {
        return new DescendingIterator();
    }

    //前向迭代器
    private class DescendingIterator implements Iterator<E> {
        private final ListItr itr = new ListItr(size());

        public boolean hasNext() {
            return itr.hasPrevious();
        }

        public E next() {
            return itr.previous();
        }

        public void remove() {
            itr.remove();
        }
    }

    @SuppressWarnings("unchecked")
    private LinkedList<E> superClone() {
        try {
            return (LinkedList<E>) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e);
        }
    }

    //拷貝操做,執行淺拷貝,只複製引用,而沒有複製引用指向的內存
    public Object clone() {
        LinkedList<E> clone = superClone();

        // Put clone into "virgin" state
        clone.first = clone.last = null;
        clone.size = 0;
        clone.modCount = 0;

        // Initialize clone with our elements
        for (Node<E> x = first; x != null; x = x.next)
            clone.add(x.item);

        return clone;
    }

    //轉換爲數組
    public Object[] toArray() {
        Object[] result = new Object[size];
        int i = 0;
        for (Node<E> x = first; x != null; x = x.next)
            result[i++] = x.item;
        return result;
    }

    //轉換爲數組
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        if (a.length < size)
            a = (T[]) java.lang.reflect.Array.newInstance(
                    a.getClass().getComponentType(), size);
        int i = 0;
        Object[] result = a;
        for (Node<E> x = first; x != null; x = x.next)
            result[i++] = x.item;

        if (a.length > size)
            a[size] = null;

        return a;
    }

    //序列化版本
    private static final long serialVersionUID = 876323262645176354L;

    //序列化
    private void writeObject(java.io.ObjectOutputStream s)
            throws java.io.IOException {
        // Write out any hidden serialization magic
        s.defaultWriteObject();

        // Write out size
        s.writeInt(size);

        // Write out all elements in the proper order.
        for (Node<E> x = first; x != null; x = x.next)
            s.writeObject(x.item);
    }

    //反序列化
    @SuppressWarnings("unchecked")
    private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
        // Read in any hidden serialization magic
        s.defaultReadObject();

        // Read in size
        int size = s.readInt();

        // Read in all elements in the proper order.
        for (int i = 0; i < size; i++)
            linkLast((E) s.readObject());
    }

    //獲取一個分割器,1.8新增
    @Override
    public Spliterator<E> spliterator() {
        return new LLSpliterator<E>(this, -1, 0);
    }

    /**
     * A customized variant of Spliterators.IteratorSpliterator
     */
    static final class LLSpliterator<E> implements Spliterator<E> {
        ···
    }

}
複製代碼

總結

  關於LinkedList的源碼,給出幾點比較重要的總結:
  1.從源碼中很明顯能夠看出,LinkedList的實現是基於雙向鏈表的,且頭結點中不存放數據。
  2.注意兩個不一樣的構造方法。無參構造方法直接創建一個僅包含head節點的空鏈表;包含Collection的構造方法,先調用無參構造方法創建一個空鏈表,然後將Collection中的數據加入到鏈表的尾部後面。
  3.在查找和刪除某元素時,源碼中都劃分爲該元素爲null和不爲null兩種狀況來處理,LinkedList中容許元素爲null。
  4.LinkedList是基於鏈表實現的,所以不存在容量不足的問題,因此這裏沒有擴容的方法。
  5.Node node(int index)方法。該方法返回雙向鏈表中指定位置處的節點,而鏈表中是沒有下標索引的,要指定位置出的元素,就要遍歷該鏈表,從源碼的實現中,咱們看到這裏有一個加速動做。源碼中先將index與長度size的一半比較,若是index<(size<<1),就只從位置0日後遍歷到位置index處,而若是index>(size<<1),就只從位置size往前遍歷到位置index處。這樣能夠減小一部分沒必要要的遍歷,從而提升必定的效率(實際上效率仍是很低)。
  6.LinkedList是基於鏈表實現的,所以插入刪除效率高,查找效率低(雖然有一個加速動做)。
  7.要注意源碼中還實現了棧和隊列的操做方法,所以也能夠做爲棧、隊列和雙端隊列來使用。

參考

數據結構(二):鏈表
LearningNotes

相關文章
相關標籤/搜索