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

關於LinkedList的源碼關注點


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

 

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

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

安全

 


底層結構就是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,前置插入spa

 

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))便可.net

 

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

相關文章
相關標籤/搜索