LinkedList源碼解讀

LinkedList

  • 介紹

    LinkedList是基于雙向鏈表實(shí)現(xiàn)的;

    隨機(jī)訪問(wèn)頭部與尾部速度快剖张;

    隨機(jī)中間值速度較慢,因?yàn)樾枰苿?dòng)指針顾犹;

    頭部與尾部插入與刪除速度快锄奢;

    中間插入就略慢一下剧腻,因?yàn)樾枰苿?dòng)指針灰伟;

    其實(shí)現(xiàn)了Deque接口;可當(dāng)一個(gè)Deque使用

  • 重要屬性

//List的大小
transient int size = 0;
//頭部節(jié)點(diǎn)
transient Node<E> first;
//尾部節(jié)點(diǎn)
transient Node<E> last;
  • add方法
public boolean add(E e) {
    linkLast(e);
    return true;
}
void linkLast(E e) {
    //獲取尾部節(jié)點(diǎn)
    final Node<E> l = last;
    //創(chuàng)建新節(jié)點(diǎn)闭翩,使其上一個(gè)節(jié)點(diǎn)指向尾部節(jié)點(diǎn)
    final Node<E> newNode = new Node<>(l, e, null);
    //更新尾部節(jié)點(diǎn)
    last = newNode;
    if (l == null)
        //如果l是空的先蒋,說(shuō)明add之前無(wú)元素寇蚊,將頭部節(jié)點(diǎn)指向新節(jié)點(diǎn)
        first = newNode;
    else
        //將原尾部節(jié)點(diǎn)指向新的節(jié)點(diǎn)
        l.next = newNode;
    size++;
    modCount++;
}

尾部添加一個(gè)節(jié)點(diǎn)步驟:

newNode.prev=last => last.next=newNode => last=newNode

ArrayList相比笔时,ArrayList可能會(huì)觸發(fā)擴(kuò)容操作(影響速度),LinkedList則是直接追加道最后一個(gè)節(jié)點(diǎn)

  • addLast方法
//與add方法邏輯一致
public void addLast(E e) {
    linkLast(e);
}
  • addFirst方法
public void addFirst(E e) {
    linkFirst(e);
}
private void linkFirst(E e) {
    //獲取頭節(jié)點(diǎn)
    final Node<E> f = first;
    //創(chuàng)建新節(jié)點(diǎn)仗岸,使其下一個(gè)節(jié)點(diǎn)指向頭節(jié)點(diǎn)
    final Node<E> newNode = new Node<>(null, e, f);
    //更新頭節(jié)點(diǎn)
    first = newNode;
    if (f == null)
        //將尾部節(jié)點(diǎn)指向新節(jié)點(diǎn)
        last = newNode;
    else
        //將原頭部節(jié)點(diǎn)指向新的節(jié)點(diǎn)
        f.prev = newNode;
    size++;
    modCount++;
}

頭部添加一個(gè)節(jié)點(diǎn)步驟:

newNode.next=first => first.prev=newNode => first=newNode

ArrayList相比允耿,ArrayList向頭部添加一個(gè)元素需要后面元素copy移位,還可能觸發(fā)擴(kuò)容扒怖;效率上LinkedList指定搞一些

  • add方法(添加到指定位置)
public void add(int index, E element) {
    //檢查index是否有越界
    checkPositionIndex(index);
    //index與size相等较锡,則是往尾部添加
    if (index == size)
        linkLast(element);
    else
        linkBefore(element, node(index));
}
//往指定節(jié)點(diǎn)succ前插入一節(jié)點(diǎn)
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++;
}

指定節(jié)點(diǎn)前插入一個(gè)新節(jié)點(diǎn)步驟:

newNode.pred=succ.prev => newNode.next=succ => succ.prev.next=newNode

ArrayList相比,ArrayList需要移位index后元素盗痒,LinkedList需要遍歷尋找節(jié)點(diǎn)

  • addAll方法
public boolean addAll(Collection<? extends E> c) {
    return addAll(size, c);
}
public boolean addAll(int index, Collection<? extends E> c) {
    checkPositionIndex(index);
    Object[] a = c.toArray();
    int numNew = a.length;
    if (numNew == 0)
        return false;
    Node<E> pred, succ;
    if (index == size) {
        succ = null;
        pred = last;
    } else {
        succ = node(index);
        pred = succ.prev;
    }
    for (Object o : a) {
        @SuppressWarnings("unchecked") E e = (E) o;
        Node<E> newNode = new Node<>(pred, e, null);
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        pred = newNode;
    }
    if (succ == null) {
        last = pred;
    } else {
        pred.next = succ;
        succ.prev = pred;
    }
    size += numNew;
    modCount++;
    return true;
}

如果是往尾部添加的話蚂蕴,直接for循環(huán)往后鏈就得了;

如果不是的話,先遍歷找到index對(duì)應(yīng)的節(jié)點(diǎn)骡楼,然后再往下鏈熔号,鏈完后,與尾部接上即可了鸟整;

ArrayList相比跨嘉,ArrayList尾部添加的話,copy一次數(shù)組吃嘿;ArrayList中間插入的話需copy兩次數(shù)組祠乃;

  • get方法
public E get(int index) {
    //檢查index是否有越界
    checkElementIndex(index);
    return node(index).item;
}
//根據(jù)index獲取節(jié)點(diǎn),通過(guò)遍歷子節(jié)點(diǎn)方式
Node<E> node(int index) {
    //判斷如果index小于size的一半兑燥,則從頭部開(kāi)始遍歷子節(jié)點(diǎn)亮瓷;否則從尾部遍歷子節(jié)點(diǎn)
    if (index < (size >> 1)) {
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

ArrayList相比,LinkedList.get效率略低降瞳,需要遍歷子節(jié)點(diǎn)查詢嘱支。

  • set方法
//根據(jù)index獲取子節(jié)點(diǎn),然后替換其值
public E set(int index, E element) {
    //檢查index是否有越界
    checkElementIndex(index);
    Node<E> x = node(index);
    E oldVal = x.item;
    x.item = element;
    return oldVal;
}

ArrayList相比挣饥,LinkedList.set效率略低除师,需要遍歷子節(jié)點(diǎn)查詢。

  • remove方法(根據(jù)元素移除)
//遍歷找到節(jié)點(diǎn)扔枫,然后移除
public boolean remove(Object o) {
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null) {
                unlink(x);
                return true;
            }
        }
    } else {
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item)) {
                unlink(x);
                return true;
            }
        }
    }
    return false;
}
//移除一個(gè)節(jié)點(diǎn)
E unlink(Node<E> x) {
    final E element = x.item;
    final Node<E> next = x.next;
    final Node<E> prev = x.prev;
    if (prev == null) {
        first = next;
    } else {
        prev.next = next;
        x.prev = null;
    }
    if (next == null) {
        last = prev;
    } else {
        next.prev = prev;
        x.next = null;
    }
    x.item = null;
    size--;
    modCount++;
    return element;
}

移除一個(gè)節(jié)點(diǎn)的步驟:

x.prev.next=x.next => x.next.prev=x.prev => x...=null

ArrayList相比汛聚,ArrayList遍歷后得到index,然后移除(需要index后元素移位)短荐,LinkedList遍歷得到節(jié)點(diǎn)倚舀,直接移除。

  • remove方法(根據(jù)index移除)
//遍歷獲取節(jié)點(diǎn)忍宋,然后移除
public E remove(int index) {
    //檢查index是否有越界
    checkElementIndex(index);
    return unlink(node(index));
}

ArrayList相比痕貌,ArrayList移除元素后index后元素移位,LinkedList是遍歷取得節(jié)點(diǎn)直接移除

  • clear方法
public void clear() {
    for (Node<E> x = first; x != null; ) {
        Node<E> next = x.next;
        x.item = null;
        x.next = null;
        x.prev = null;
        x = next;
    }
    first = last = null;
    size = 0;
    modCount++;
}

ArrayList.clear 差不多糠排,都是遍歷置空數(shù)據(jù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末舵稠,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子入宦,更是在濱河造成了極大的恐慌哺徊,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件云石,死亡現(xiàn)場(chǎng)離奇詭異唉工,居然都是意外死亡研乒,警方通過(guò)查閱死者的電腦和手機(jī)汹忠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人宽菜,你說(shuō)我怎么就攤上這事谣膳。” “怎么了铅乡?”我有些...
    開(kāi)封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵继谚,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我阵幸,道長(zhǎng)花履,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任挚赊,我火速辦了婚禮诡壁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘荠割。我一直安慰自己妹卿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布蔑鹦。 她就那樣靜靜地躺著夺克,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嚎朽。 梳的紋絲不亂的頭發(fā)上铺纽,一...
    開(kāi)封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音哟忍,去河邊找鬼室囊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛魁索,可吹牛的內(nèi)容都是我干的融撞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼粗蔚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼尝偎!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起鹏控,我...
    開(kāi)封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤致扯,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后当辐,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體抖僵,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年缘揪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了耍群。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片义桂。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蹈垢,靈堂內(nèi)的尸體忽然破棺而出慷吊,到底是詐尸還是另有隱情,我是刑警寧澤曹抬,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布溉瓶,位于F島的核電站,受9級(jí)特大地震影響谤民,放射性物質(zhì)發(fā)生泄漏堰酿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一张足、第九天 我趴在偏房一處隱蔽的房頂上張望胞锰。 院中可真熱鬧,春花似錦兢榨、人聲如沸嗅榕。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)凌那。三九已至,卻和暖如春吟逝,著一層夾襖步出監(jiān)牢的瞬間帽蝶,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工块攒, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留励稳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓囱井,卻偏偏與公主長(zhǎng)得像驹尼,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子庞呕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353