【數據結構】2.java源碼關於LinkedList

關於LinkedList的源碼關注點


1.從底層數據結構,擴容策略
2.LinkedList的增刪改查
3.特殊處理重點關注
4.遍歷的速度,隨機訪問和iterator訪問效率對比

 

1.從底層數據結構,擴容策略

構造函數不做任何操作,只要再add的時候進行數據初始化操作,以操作推動邏輯,而且linkedlist是一個雙向鏈表,所以可以向前向後雙向遍歷
由於構造函數並沒有任何操作,其實這裏我們可以先看新增操作,並且因爲用的是鏈表所以無法隨機訪問,這裏隨機讀取就會比較慢

 


底層結構就是size,首節點,尾節點,還有就是一個List都有的共性就是modCount,這值用來記錄這個list被修改了多少次

 

 2.LinkedList的增刪改查

 2.1 add操作,linklast

 

Add操作的實質就是進行linklast操作

linklast的操作就是再最後吧節點添加到尾部,並修正size大小

 

 

 

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

 

我們看看如果是在指定的位置插入元素的操作
首先要確認index再指定範圍內
這裏有個小優化,如果是在末尾進行添加的話,我們直接調用linklast就可以了
如果不是最後一個,那麼首先要獲取指定位置的node節點,我們遍歷指定位置的時候
可以確定index的位置如果過半了,那麼就從後往前,如果沒有過半,那麼就從前往後
1.直接再index創建一個節點,然後前後合併一下
2.吧原來的index位置的節點斷開,吧這個節點的pre指向新節點
3.判斷前置節點是否到頭了,爲空
4.把前置節點的next指向新節點

 先看看node定位操作

 

 

 然後我們看看linkbefore,前置插入

 

public 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.next = newNode;
        size++;
        modCount++;
    }

那麼我們需要插入到指定的位置的方法就可以很簡單的實現了
Linkbefore(e, node(index))即可

 

2.2 刪除

 

查看源碼,比較remove(),remove(object),remove(index)等等操作,歸根到底還是一個unlink操作
我們需要對指定的節點進行unlink操作
就2步操作
1.當前節點的前一個節點指向當前節點的下一個節點,說白了node.pre.next = node.next;
2.當前節點的下一個節點的前置節點指向當前節點的上一個節點:node.next.pre = node.pre;
其他細節部分就是首尾節點的處理

 

 

public E unlink(Node<E> node) {
        // assert x != null;
        //這裏需要操作的就是三個節點,前置節點,當前節點,後置節點
        final E element = node.item;
        final Node<E> prev = node.prev;
        final Node<E> next = node.next;

        //當前節點的前一個節點指向當前節點的下一個節點,說白了node.pre.next = node.next;
        if (prev == null) {
            //避免首節點操作
            first = next;
        } else {
            prev.next = next;
            node.prev = null; //斷開原始連接
        }

        //當前節點的下一個節點的前置節點指向當前節點的上一個節點:node.next.pre = node.pre;
        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            node.next = null;
        }

        //清除當前節點
        node.item = null;
        size--;
        modCount++;
        return element;
    }

其餘操作基本就是調用unlink方法進行操作

 

 修改set和獲取get就不多說了,就注意一點就是set操作的時候,會返回舊值,並且這兩個操作不會修改modCount值,也就是不會產生鏈表變動

 

 3.特殊處理重點關注,iterator,序列化

 

 

對於iterator這個就不多說了,其實還是調用上面的那些方法,遍歷也就是next和pre和循環遍歷沒差別
但是注意一點就是通過迭代器進行remove和add是可以的,但是注意一點,如果使用迭代器進行remove或者add操作的通過,還使用了一般的remove和add那麼就會使迭代器失效


序列化這裏我們先只做一個瞭解,後續開章節專門學習一下java的序列化:

進行序列化、反序列化時,虛擬機會首先試圖調用對象裏的writeObject和readObject方法,進行用戶自定義的序列化和反序列化。如果沒有這樣的方法,那麼默認調用的是ObjectOutputStream的defaultWriteObject以及ObjectInputStream的defaultReadObject方法。換言之,利用自定義的writeObject方法和readObject方法,用戶可以自己控制序列化和反序列化的過程。
---------------------
版權聲明:本文爲CSDN博主「zthgreat」的原創文章,遵循CC 4.0 by-sa版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/u014634338/article/details/78165127

 

 

4.遍歷的速度,隨機訪問和iterator訪問效率對比

這個問題其實也可以捨棄掉了,這裏遍歷的實質還是使用鏈表的遍歷方式進行遍歷

 

 

5.是否支持多線程

LinkedList 是線程不安全的,允許元素爲null的雙向鏈表。

 

參考:https://blog.csdn.net/u014634338/article/details/78165127

 

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