LinkedList源碼分析

LinkedList介紹

JangGwa帶你再熟悉一下LinkedList颗圣,首先簡單介紹下LinkedList我纪。

1.基于雙向鏈表實現(xiàn)脓匿,鏈表無容量限制遍略。

2.LinkedList是非線程安全的压鉴。

3.實現(xiàn)了List接口崖咨,實現(xiàn)了get(int location)、remove(int location)等根據(jù)索引值來獲取油吭、刪除節(jié)點的函數(shù)击蹲。

4.實現(xiàn)了Deque接口,可以將LinkedList當做雙端隊列使用上鞠。

5.實現(xiàn)了Cloneable接口际邻,能被克隆

6.實現(xiàn)了Serializable接口芍阎,支持序列化世曾。

LinkedList源碼解析

LinkedList繼承了AbstractSequentialList并實現(xiàn)了List,Deque, Cloneable, java.io.Serializable 接口,上面做了相應的介紹就不再闡述了谴咸。關鍵我們看兩個重要的屬性headersize轮听。

header:雙向鏈表的表頭,它是雙向鏈表節(jié)點所對應的類Entry的實例岭佳。Entry中包含成員變量: previous, next, element血巍。其中,previous是該節(jié)點的上一個節(jié)點珊随,next是該節(jié)點的下一個節(jié)點述寡,element是該節(jié)點所包含的值舀锨。

size:雙向鏈表中節(jié)點的個數(shù)

public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
// 鏈表的表頭,表頭不包含任何數(shù)據(jù)田篇。Entry是個鏈表類數(shù)據(jù)結(jié)構礁鲁。
private transient Entry<E> header = new Entry<E>(null, null, null);

// LinkedList中元素個數(shù)
private transient int size = 0;

// 默認構造函數(shù):創(chuàng)建一個空的鏈表
public LinkedList() {
    header.next = header.previous = header;
}

// 包含“集合”的構造函數(shù):創(chuàng)建一個包含“集合”的LinkedList
public LinkedList(Collection<? extends E> c) {
    this();
    addAll(c);
}

雙向鏈表的節(jié)點所對應的數(shù)據(jù)結(jié)構

private static class Entry<E> {
    // 當前節(jié)點所包含的值
    E element;
    // 下一個節(jié)點
    Entry<E> next;
    // 上一個節(jié)點
    Entry<E> previous;

    Entry(E element, Entry<E> next, Entry<E> previous) {
        this.element = element;
        this.next = next;
        this.previous = previous;
    }
}

獲取鏈表指定位置節(jié)點

將index與長度size的一半比較螟炫,如果index<size/2波附,就只從位置0往后遍歷到位置index處,而如果index>size/2昼钻,就只從位置size往前遍歷到位置index處掸屡。

private Entry<E> entry(int index) {
    if (index < 0 || index >= size)
        throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
    Entry<E> e = header;
    // 獲取index處的節(jié)點。
    // 若index < 雙向鏈表長度的1/2,則從前先后查找;
    // 否則然评,從后向前查找仅财。
    if (index < (size >> 1)) {
        for (int i = 0; i <= index; i++)
            e = e.next;
    } else {
        for (int i = size; i > index; i--)
            e = e.previous;
    }
    return e;
}

get()和set()

 // 返回LinkedList指定位置的元素
public E get(int index) {
    return entry(index).element;
}

// 設置index位置對應的節(jié)點的值為element
public E set(int index, E element) {
    Entry<E> e = entry(index);
    E oldVal = e.element;
    e.element = element;
    return oldVal;
}

添加

// 將e添加到當前節(jié)點的前面
    public void add(E e) {
        checkForComodification();
        lastReturned = header;
        addBefore(e, next);
        nextIndex++;
        expectedModCount++;
    }

// 將元素添加到LinkedList的起始位置
public void addFirst(E e) {
    addBefore(e, header.next);
}

// 將元素添加到LinkedList的結(jié)束位置
public void addLast(E e) {
    addBefore(e, header);
}

// 將元素(E)添加到LinkedList中
public boolean add(E e) {
    // 將節(jié)點(節(jié)點數(shù)據(jù)是e)添加到表頭(header)之前。
    // 即沾瓦,將節(jié)點添加到雙向鏈表的末端满着。
    addBefore(e, header);
    return true;
}

刪除

// 從LinkedList中刪除元素(o)
public boolean remove(Object o) {
    if (o==null) {
        // 若o為null的刪除情況
        for (Entry<E> e = header.next; e != header; e = e.next) {
            if (e.element==null) {
                remove(e);
                return true;
            }
        }
    } else {
        // 若o不為null的刪除情況
        for (Entry<E> e = header.next; e != header; e = e.next) {
            if (o.equals(e.element)) {
                remove(e);
                return true;
            }
        }
    }
    return false;
}

// 將節(jié)點從鏈表中刪除
private E remove(Entry<E> e) {
    if (e == header)
        throw new NoSuchElementException();

    E result = e.element;
    e.previous.next = e.next;
    e.next.previous = e.previous;
    e.next = e.previous = null;
    e.element = null;
    size--;
    modCount++;
    return result;
}

清空LinkedList

// 清空雙向鏈表
public void clear() {
    Entry<E> e = header.next;
    // 從表頭開始,逐個向后遍歷贯莺;對遍歷到的節(jié)點執(zhí)行一下操作:
    // (01) 設置前一個節(jié)點為null 
    // (02) 設置當前節(jié)點的內(nèi)容為null 
    // (03) 設置后一個節(jié)點為“新的當前節(jié)點”
    while (e != header) {
        Entry<E> next = e.next;
        e.next = e.previous = null;
        e.element = null;
        e = next;
    }
    header.next = header.previous = header;
    // 設置大小為0
    size = 0;
    modCount++;
}

克隆

public Object clone() {
    LinkedList<E> clone = null;
    // 克隆一個LinkedList克隆對象
    try {
        clone = (LinkedList<E>) super.clone();
    } catch (CloneNotSupportedException e) {
        throw new InternalError();
    }

    // 新建LinkedList表頭節(jié)點
    clone.header = new Entry<E>(null, null, null);
    clone.header.next = clone.header.previous = clone.header;
    clone.size = 0;
    clone.modCount = 0;

    // 將鏈表中所有節(jié)點的數(shù)據(jù)都添加到克隆對象中
    for (Entry<E> e = header.next; e != header; e = e.next)
        clone.add(e.element);

    return clone;
}

總結(jié)

  • LinkedList的實現(xiàn)是基于雙向循環(huán)鏈表的风喇。有一個重要的內(nèi)部類:Entry,是雙向鏈表節(jié)點所對應的數(shù)據(jù)結(jié)構缕探。
  • 不存在容量不足的問題魂莫。
  • LinkedList是基于鏈表實現(xiàn)的,因此插入刪除效率高爹耗,查找效率低耙考。
  • LinkedList的克隆函數(shù),即是將全部元素克隆到一個新的LinkedList對象中潭兽。
  • LinkedList實現(xiàn)java.io.Serializable倦始。當寫入到輸出流時,先寫入“容量”山卦,再依次寫入“每一個節(jié)點保護的值”鞋邑;當讀出輸入流時,先讀取“容量”账蓉,再依次讀取“每一個元素”枚碗。
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市铸本,隨后出現(xiàn)的幾起案子肮雨,更是在濱河造成了極大的恐慌,老刑警劉巖箱玷,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怨规,死亡現(xiàn)場離奇詭異陌宿,居然都是意外死亡,警方通過查閱死者的電腦和手機椅亚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門限番,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人呀舔,你說我怎么就攤上這事±┑疲” “怎么了媚赖?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長珠插。 經(jīng)常有香客問我惧磺,道長,這世上最難降的妖魔是什么捻撑? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任磨隘,我火速辦了婚禮,結(jié)果婚禮上顾患,老公的妹妹穿的比我還像新娘番捂。我一直安慰自己,他們只是感情好江解,可當我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布设预。 她就那樣靜靜地躺著,像睡著了一般犁河。 火紅的嫁衣襯著肌膚如雪鳖枕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天桨螺,我揣著相機與錄音宾符,去河邊找鬼。 笑死灭翔,一個胖子當著我的面吹牛魏烫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播缠局,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼则奥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了狭园?” 一聲冷哼從身側(cè)響起读处,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎唱矛,沒想到半個月后罚舱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體井辜,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年管闷,在試婚紗的時候發(fā)現(xiàn)自己被綠了粥脚。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡包个,死狀恐怖刷允,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碧囊,我是刑警寧澤树灶,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站糯而,受9級特大地震影響天通,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜熄驼,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一像寒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瓜贾,春花似錦诺祸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至实束,卻和暖如春奥秆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背咸灿。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工构订, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人避矢。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓悼瘾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親审胸。 傳聞我的和親對象是個殘疾皇子亥宿,可洞房花燭夜當晚...
    茶點故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容