Java集合之LinkedList


上一篇寫的是ArrayList,這一篇寫一下LinkedList.

開宗明義,因為Vector已經被廢棄了,所以list家族只剩下ArrayList和LinkedList兩兄弟了,這里直接對比一下二位:

ArrayList基於動態數組的實現,它長於隨機訪問元素,但是在中間插入和移除元素時較慢

LinkedList基於鏈表實現,在List中間進行插入和刪除的代價較低,提供了優化的順序訪問。LinkedList在隨機訪問方面相對比較慢,但是它的特性集較ArrayList更大。

那么,到底特性集大在哪里呢?

這就是這篇博客的重點,在JAVA中,LinkedList可以作為我們最經常使用的兩種數據結構來使用:棧和隊列。Java中實現隊列一般都是用LinkedList實現。

這是因為LinkedList的實現是一個雙向鏈表,所以無論是FIFO還是FILO都可以實現。

(1)初始化:

先看一下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;

這就是我們很早學過的雙向鏈表的實現基本要素。

看一下Node節點的定義,回憶一下雙向鏈表,后邊的操作就不再貼代碼了,因為都是數據結構第一節課學的。

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

這里注意一下前面的修飾符 transient 關鍵字:

當對象被序列化時(寫入字節序列到目標文件)時,transient阻止實例中那些用此關鍵字聲明的變量持久化;當對象被反序列化時(從源文件讀取字節序列進行重構),這樣的實例變量值不會被持久化和恢復。

為什么要有這個關鍵字呢?因為我們要告訴虛擬機,這三個成員不是LinkedList的永久性變量。點到為止,后續在JVM的總結中會專門介紹一下各種關鍵字和虛擬機的關系。

(2)用作棧、隊列和雙向隊列

對於這三種不同的數據結構的操作,LinkedList規定了6種基本動作

getFirst()
getLast()
removeFirst()
removeLast()
addFirst()
addLast()

其中removeFirst()會調用unlinkFirst()函數,removeLast會調用unlinkLast()函數

下面看看是如何實現的棧和隊列的功能。

用作棧:

public void push(E e) {
    addFirst(e);
}
public E pop() {
    return removeFirst();
}
View Code

用作隊列:

public E peek() {
    final Node<E> f = first;
    return (f == null) ? null : f.item;
}
public E poll() {
    final Node<E> f = first;
    return (f == null) ? null : unlinkFirst(f);
}
public boolean offer(E e) {
    return add(e);
}
View Code

用作雙端隊列:

public boolean offerFirst(E e) {
    addFirst(e);
    return true;
}
public boolean offerLast(E e) {
    addLast(e);
    return true;
}
public E peekFirst() {
    if (size == 0)
        return null;
    return getFirst();
}
public E peekLast() {
    if (size == 0)
        return null;
    return getLast();
}
public E pollFirst() {
    if (size == 0)
        return null;
    return removeFirst();
}
public E pollLast() {
    if (size == 0)
        return null;
    return removeLast();
}
View Code

因為都是最簡單的操作,都是望文生義的函數,所以就沒寫注釋並且折疊代碼了。

(3)其實沒什么好寫的

寫完第二篇了,最大的感覺這些東西直接看文檔就可以了,但是自己再看一遍源碼也挺有趣,所以慢慢寫吧,看一點寫一點,從集合類到IO到並發到JVM,希望可以寫完。

之前讀了一本關於並發的書,最大的感慨就是數據結構太神奇,被各種思路使用的各種形式的數據結構,尤其是Disruptor使用的環形隊列給驚艷到了。

讀研以來,一直在看機器學習、並發編程和設計模式的知識,實驗室項目從前端都后台到算法都嘗試過,但是都不夠深入,浮於表面,沒什么用。

於是寒假反思了一下,開學又和曉暉聊了聊,感覺自己還是更適合做個軟件工程師,而不是算法工程師。

所以趁着在學校,把一切都推倒重來,從零開始,夯實基礎。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM