Java底層實現LinkedList 鏈表

LinkedList 鏈表


1、什麼是鏈表

鏈表,使用“鏈子”將數據組合起來,這裏的鏈子指的就是引用或者指針。鏈子存儲在哪裏呢?節點(Node)中,我們把節點封裝在類中。即

class Node{
    E e;
    Node next;
}

也就形成了這樣的數據結構

1.1、同數組的區別

上面就是鏈表,同動態數組不同,鏈表纔算是真正的動態

動態數組

  • 優點:具備隨機訪問能力,直接根據地址尋址一步完成
  • 缺點:不具備真正的動態性,底層依然依靠固定容量的數組

鏈表

  • 優點:具有真正的動態性,完全根據用戶的數據建立節點
  • 缺點:缺少了隨機訪問能力,不適合應對查詢元素頻繁的場景

1.2、節點的實現

由於設計鏈表類的時候,節點作爲鏈表存儲數據的核心。那麼節點類就要作爲鏈表類的子類,所以具體的Java實現如下:

public class LinkedList<E> {
    private class Node{  //
        public Node(E e, Node node) {
            this.e = e;
            this.next = node;
        }

        public Node(E e) {
            this(e, null);
        }

        public Node() {
            this(null, null);
        }

        @Override
        public String toString() {
            return e.toString();
        }

        E e;
        Node next;
    }
}

2、鏈表的方法實現

幾乎所有的數據結構的實現都避免不了增刪改查四中基本操作,下面分別實現一下。

寫在前面: 爲了更優化添加元素或者刪除中對頭結點的另外操作,這裏我引入虛擬頭結點(dummyNode)。

2.1、增加元素

增加元素最基本的操作就是向某一個“索引”位置添加元素。

步驟:

  1. 找到要插入位置的前一個節點pre
  2. 新增節點,並指向pre節點的下一個節點
  3. 將pre節點指向新的節點
由於我們需要索引到待添加元素的前一個位置,所以我們起始的節點放在虛擬頭結點上。這樣就可以循環index找到待添加位置的前一個位置。

程序實現

public void add(int index, E e) {
    if (index < 0 || index > size)  //越界判斷
        throw new IllegalArgumentException("add is error, index need index < 0 || index > size ");
    table pre = dummyHead;  //起始從虛頭開始
    for (int i = 0; i < index; ++i)   //找到插入位置的前一個節點
        pre = pre.next;      
    pre.next = new table(e, pre.next);
    size++;
}

2.2、刪除元素

步驟:

  1. 找到索引位置的前一個節點pre
  2. pre節點指向pre節點的下一節點的下一個節點
  3. 斷開待刪除節點與其下一個節點的連接,刪除的節點會被內存管理機制自動銷燬
和添加元素相同,我們需要先找到待刪除位置的前一個位置,所以依然以虛擬頭節點作爲起始節點。

程序實現:

public E remove(int index){
    if (index < 0 || index > size)
        throw new IllegalArgumentException("set is error, index need index < 0 || index > size ");
    table pre = dummyHead;
    for (int i = 0; i < index; ++i)  //找到待刪除節點的前一個節點
        pre = pre.next;
    size--;
    table retNode = pre.next; //保存待刪除節點,後面還要返回
    pre.next = retNode.next;
    retNode.next = null;  //斷開連接
    return retNode.e;
}

寫在後面:
在某些場景中,我們並不需要保留這個節點,爲了使代碼更加簡潔易懂我們可以做以下處理。

這種可以應用在LeetCode中,因爲在代碼執行完成以後,所有都會被銷燬。

public void remove(int index){
    if (index < 0 || index > size)
        throw new IllegalArgumentException("set is error, index need index < 0 || index > size ");
    table pre = dummyHead;
    for (int i = 0; i < index; ++i)
        pre = pre.next;
    size--;
    pre.next = pre.next.next;  //直接刪除
}

2.3、改變元素

改變元素就比較簡單,直接找到位置進行更改元素就可以。同增加元素和刪除元素不同,改變元素不需找到前一個位置,所以起始位置就是虛擬頭節點的下一個位置。

程序實現:

public void set(int index, E e) {
    if (index < 0 || index > size)
        throw new IllegalArgumentException("set is error, index need index < 0 || index > size ");
    table pre = dummyHead.next;  //起始位置
    for (int i = 0; i < index; ++i)  //找到元素
        pre = pre.next;
    pre.e = e;   //改變元素
}

2.4、查詢元素

和其他數據結構相同,包含三種查詢。

  1. find(E e) 查詢元素e所在位置
  2. contains(E e) 查詢是否包含元素,同find代碼邏輯相同
  3. get(int index) 查詢index位置上的元素
/**    是否包含元素    **/
public boolean contains(E e) {
    table currentTable = dummyHead.next;
    while (currentTable != null) {
        if (currentTable.e == e)
            return true;
        currentTable = currentTable.next;
    }
    return false;
}
/**    查找元素所在位置    **/
public int find(E e) {
    int index = 0;
    table currentTable = dummyHead.next;
    while (currentTable != null) {
        if (currentTable.e == e)
            return index;
        index++;
        currentTable = currentTable.next;
    }
    return -1;
}
/**      查詢index位置的元素    **/
    public E get(int index) {
        if (index < 0 || index > size)
            throw new IllegalArgumentException("get is error, index need index < 0 || index > size ");
        table pre = dummyHead.next;
        for (int i = 0; i < index; ++i)
            pre = pre.next;
        return pre.e;
    }

3、時間複雜度分析

對於鏈表來說,最大的優勢在於其動態性,所以在頭部進行的所有操作時間複雜度最低O(1)級別,其他位置的操作均與索引位置位置有關(因爲要先找到要操作的位置)。由此特性,我們可以清楚的看出,用鏈表實現棧的數據結構再合適不過啦。

最後

更多有關數據結構與算法的精彩內容,歡迎大家查看我的主頁:曲怪曲怪

也歡迎大家關注我的微信公衆號:TeaUrn,我在那裏等你哦。

源碼地址:可在公衆號內回覆 數據結構與算法源碼 即可獲得。

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