欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的LinkedList底層源碼分析

 更新時(shí)間:2023年12月15日 09:19:37   作者:愛(ài)喝咖啡的程序員  
這篇文章主要介紹了Java中的LinkedList底層源碼分析,底層基于雙向鏈表,往LinkedList中間插入元素時(shí),不需要移動(dòng)大量的元素,只需要修改前后節(jié)點(diǎn)的指針,速度快,需要的朋友可以參考下

一. 基本原理和優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

1.底層基于雙向鏈表,往LinkedList中間插入元素時(shí),不需要移動(dòng)大量的元素,只需要修改前后節(jié)點(diǎn)的指針,速度快。

2.適合頻繁、大量的插入元素,不會(huì)導(dǎo)致頻繁的擴(kuò)容和拷貝元素。插入元素,只不過(guò)就是把新的元素掛到舊元素下面。

缺點(diǎn):

1.不適合讀取隨機(jī)位置的元素,比如list.get(10),因?yàn)樾枰闅v鏈表,直到找到這個(gè)位置上的元素為止。

二. 源碼分析

2.1 add

默認(rèn)在雙向鏈表的尾部插入一個(gè)元素

public boolean add(E e) {
	linkLast(e);
	return true;
}
void linkLast(E e) {
	final Node<E> l = last;
	final Node<E> newNode = new Node<>(l, e, null);
	last = newNode;
	if (l == null)
		first = newNode;
	else
		l.next = newNode;
	size++;
	modCount++;
}

2.2 node

在雙向鏈表中,找到目標(biāo)下標(biāo)對(duì)應(yīng)的節(jié)點(diǎn)。這里可以學(xué)習(xí)鏈表的遍歷方式。

Node<E> node(int index) {
	// assert isElementIndex(index);
	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;
	}
}

首先,通過(guò)index < (size >> 1),判斷待尋找的節(jié)點(diǎn)在雙向鏈表的前半部分,還是后半部分。

如果是前半部分,則會(huì)從雙向鏈表的頭節(jié)點(diǎn)開(kāi)始遍歷,通過(guò)節(jié)點(diǎn)的next指針,不斷的向后尋找節(jié)點(diǎn)。→

如果是后半部分,則會(huì)從雙向鏈表的尾節(jié)點(diǎn)開(kāi)始遍歷,通過(guò)節(jié)點(diǎn)的prev指針,不斷的向前尋找節(jié)點(diǎn)。←

2.3 add(int index, E element)

在指定元素的前面,插入一個(gè)元素。比如現(xiàn)在想要在隊(duì)尾插入一個(gè)元素。

void linkBefore(E e, Node<E> succ) {
	// assert succ != null;
	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++;
}

succ指向隊(duì)尾元素,succ.prev表示隊(duì)尾節(jié)點(diǎn)前面的那個(gè)節(jié)點(diǎn)(倒數(shù)第二個(gè)節(jié)點(diǎn))。

首先,創(chuàng)建一個(gè)新節(jié)點(diǎn),讓新節(jié)點(diǎn)的prev指針指向倒數(shù)第二個(gè)節(jié)點(diǎn),新節(jié)點(diǎn)的next指針指向隊(duì)尾節(jié)點(diǎn)。

接著,讓隊(duì)尾節(jié)點(diǎn)指的prev指向新節(jié)點(diǎn)。

最后,把倒數(shù)第二個(gè)節(jié)點(diǎn)的next指針指向新節(jié)點(diǎn)。

2.4 get

獲取一個(gè)隨機(jī)位置的節(jié)點(diǎn)中的值。

public E get(int index) {
	checkElementIndex(index);
	return node(index).item;
}

隨機(jī)讀取是ArrayList的強(qiáng)項(xiàng), 因?yàn)锳rrayList底層基于數(shù)組實(shí)現(xiàn),通過(guò)下標(biāo)能快速找到對(duì)應(yīng)的內(nèi)存地址,接著直接讀取內(nèi)存地址中的值。

隨機(jī)讀取是LinkedList弱項(xiàng),LinkedList底層基于雙向鏈表實(shí)現(xiàn),它沒(méi)辦法通過(guò)下標(biāo),直接找到內(nèi)存地址,必須從頭、尾節(jié)點(diǎn)開(kāi)始,借助節(jié)點(diǎn)的prev和next指針,不斷的向前或向后尋找,直到找到元素為止。

node()方法的代碼之前已經(jīng)學(xué)習(xí)過(guò)了,先大致的判斷目標(biāo)節(jié)點(diǎn)距離頭、尾節(jié)點(diǎn),哪個(gè)節(jié)點(diǎn)更近,盡量的減少查詢(xún)的次數(shù),接著就是借助頭尾節(jié)點(diǎn),不斷的向前或向后找,比如從頭節(jié)點(diǎn),不斷的向后找。

2.5 getFirst

返回頭節(jié)點(diǎn)的值。如果頭節(jié)點(diǎn)為空,則拋出異常。

public E getFirst() {
	final Node<E> f = first;
	if (f == null)
		throw new NoSuchElementException();
	return f.item;
}

2.6 peek

返回頭節(jié)點(diǎn)的值,頭節(jié)點(diǎn)不需要出隊(duì)。

peek與getFirst的區(qū)別:如果不存在頭節(jié)點(diǎn),peek會(huì)返回null,而getFirst會(huì)直接報(bào)錯(cuò)。

public E peek() {
    final Node<E> f = first;
    return (f == null) ? null : f.item;
}

2.7 getLast

返回尾部節(jié)點(diǎn)的值。

public E getLast() {
	final Node<E> l = last;
	if (l == null)
		throw new NoSuchElementException();
	return l.item;
}

2.8 removeLast

刪除隊(duì)尾節(jié)點(diǎn)。

public E removeLast() {
	final Node<E> l = last;
	if (l == null)
		throw new NoSuchElementException();
	return unlinkLast(l);
}
return xprivate E unlinkLast(Node<E> l) {
	// assert l == last && l != null;
	final E element = l.item;
	final Node<E> prev = l.prev;
	l.item = null;
	l.prev = null; // help GC
	last = prev;
	if (prev == null)
		first = null;
	else
		prev.next = null;
	size--;
	modCount++;
	return element;
};

通過(guò)last指針找到隊(duì)尾元素,斷開(kāi)隊(duì)尾元素與倒數(shù)第二個(gè)元素的指針指向,last指針指向倒數(shù)第二個(gè)元素,作為新的隊(duì)尾元素。

此時(shí),原隊(duì)尾節(jié)點(diǎn)的next指針等于null,item等于null,prev等于null,且沒(méi)有被任何節(jié)點(diǎn)指向,接著就靠JVM來(lái)進(jìn)行垃圾回收了。

2.9 removeFirst

刪除隊(duì)頭節(jié)點(diǎn)。

public E removeFirst() {
	final Node<E> f = first;
	if (f == null)
		throw new NoSuchElementException();
	return unlinkFirst(f);
}
private E unlinkFirst(Node<E> f) {
	// assert f == first && f != null;
	final E element = f.item;
	final Node<E> next = f.next;
	f.item = null;
	f.next = null; // help GC
	first = next;
	if (next == null)
		last = null;
	else
		next.prev = null;
	size--;
	modCount++;
	return element;
}

把隊(duì)列的頭節(jié)點(diǎn)與第二個(gè)節(jié)點(diǎn)之前的指針指向全部斷開(kāi),讓JVM來(lái)回收頭節(jié)點(diǎn)。

接著,讓first指針原隊(duì)列的第二個(gè)節(jié)點(diǎn),作為隊(duì)列新的頭結(jié)點(diǎn)。

2.10 remove(int index)

刪除指定下標(biāo)的節(jié)點(diǎn)。

public E remove(int index) {
	checkElementIndex(index);
	return unlink(node(index));
}
E unlink(Node<E> x) {
        // assert x != null;
        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;
    }

首先,通過(guò)node方法,遍歷鏈表,找到待刪除的節(jié)點(diǎn)。

接著,解除待刪除節(jié)點(diǎn),對(duì)于左右兩邊節(jié)點(diǎn)的所有指針指向。讓左右兩邊的節(jié)點(diǎn)的next和prev指針互相指向。

最后,由JVM回收這個(gè)沒(méi)有任何人指向的節(jié)點(diǎn)。

三. 總結(jié)

LinkedList是一個(gè)基于雙向鏈表實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu),對(duì)于隊(duì)頭和隊(duì)尾節(jié)點(diǎn)來(lái)說(shuō),無(wú)論是插入、刪除還是讀取節(jié)點(diǎn)的值,其實(shí)都是很輕松的。并且,默認(rèn)從隊(duì)尾插入節(jié)點(diǎn),從隊(duì)頭獲取節(jié)點(diǎn),所以L(fǎng)inkedList天然就可以作為隊(duì)列來(lái)使用。

由于基于雙向鏈表實(shí)現(xiàn),所以無(wú)論你怎么插入數(shù)據(jù),LinkedList的性能都很不錯(cuò),不用擔(dān)心擴(kuò)容,移動(dòng)大量元素等問(wèn)題,性能上很好。

但是呢,在鏈表的中間插入元素,比在隊(duì)頭和隊(duì)尾插入元素的性能要差一些,這是因?yàn)殛?duì)頭和隊(duì)尾分別有first和last指針指向著它們,如果要在鏈表的中間指定位置插入元素,首先要遍歷鏈表,找到目標(biāo)元素,然后才能修改左右兩邊節(jié)點(diǎn)的指針,插入節(jié)點(diǎn)。

此外,如果要隨機(jī)獲取某個(gè)位置的元素,尤其是鏈表內(nèi)節(jié)點(diǎn)的數(shù)量很多的時(shí)候,由于需要遍歷鏈表,所以性能比較差。

到此這篇關(guān)于Java中的LinkedList底層源碼分析的文章就介紹到這了,更多相關(guān)LinkedList底層源碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java使用JOptionPane猜數(shù)字游戲

    java使用JOptionPane猜數(shù)字游戲

    這篇文章主要為大家詳細(xì)介紹了java使用JOptionPane猜數(shù)字游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • Java中的線(xiàn)程同步與ThreadLocal無(wú)鎖化線(xiàn)程封閉實(shí)現(xiàn)

    Java中的線(xiàn)程同步與ThreadLocal無(wú)鎖化線(xiàn)程封閉實(shí)現(xiàn)

    這篇文章主要介紹了Java中的線(xiàn)程同步與ThreadLocal無(wú)鎖化線(xiàn)程封閉實(shí)現(xiàn),Synchronized關(guān)鍵字與ThreadLocal變量的使用是Java中線(xiàn)程控制的基礎(chǔ),需要的朋友可以參考下
    2016-03-03
  • SpringBoot或SpringAI對(duì)接DeepSeek大模型的詳細(xì)步驟

    SpringBoot或SpringAI對(duì)接DeepSeek大模型的詳細(xì)步驟

    這篇文章主要介紹了DeepSeek智能助手的使用方法和步驟,包括引入庫(kù)、配置環(huán)境變量和配置,文章詳細(xì)描述了流式請(qǐng)求和非流式請(qǐng)求的實(shí)現(xiàn)方式,需要的朋友可以參考下
    2025-02-02
  • Struts2之Validator驗(yàn)證框架的詳細(xì)介紹

    Struts2之Validator驗(yàn)證框架的詳細(xì)介紹

    Struts2中提供了數(shù)據(jù)校驗(yàn)驗(yàn)證數(shù)據(jù)例如驗(yàn)證郵件、數(shù)字等,本篇文章介紹了Struts2之Validator的詳細(xì)介紹,有興趣的可以了解一下。
    2017-03-03
  • 在SpringBoot中更改默認(rèn)端口的方法總結(jié)

    在SpringBoot中更改默認(rèn)端口的方法總結(jié)

    在本文中,小編將帶大家學(xué)習(xí)如何在 Spring Boot 中更改默認(rèn)端口,默認(rèn)情況下,嵌入式 Web 服務(wù)器使用 8080端口來(lái)啟動(dòng) Spring 引導(dǎo)應(yīng)用程序,有幾種方法可以更改該端口,文中介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • springBoot項(xiàng)目配置文件加載優(yōu)先級(jí)及同配置覆蓋問(wèn)題詳解

    springBoot項(xiàng)目配置文件加載優(yōu)先級(jí)及同配置覆蓋問(wèn)題詳解

    SpringBoot配置?件可以放置在多種路徑下,不同路徑下的配置優(yōu)先級(jí)有所不同,下面這篇文章主要給大家介紹了關(guān)于springBoot項(xiàng)目配置文件加載優(yōu)先級(jí)及同配置覆蓋問(wèn)題的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • 一文詳解JavaWeb過(guò)濾器(Filter)

    一文詳解JavaWeb過(guò)濾器(Filter)

    本文主要介紹了一文詳解JavaWeb過(guò)濾器(Filter),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • Java中Set與List的關(guān)系與區(qū)別介紹

    Java中Set與List的關(guān)系與區(qū)別介紹

    這篇文章主要介紹了Java中Set與List的關(guān)系與區(qū)別介紹,本文總結(jié)它們兩個(gè)接口都是繼承自Collection、它們之間的存儲(chǔ)方式不一樣,需要的朋友可以參考下
    2015-03-03
  • Spring Cloud Zuul的重試配置詳解

    Spring Cloud Zuul的重試配置詳解

    這篇文章主要介紹了Spring Cloud Zuul的重試配置詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-04-04
  • 詳解在Java程序中運(yùn)用Redis緩存對(duì)象的方法

    詳解在Java程序中運(yùn)用Redis緩存對(duì)象的方法

    這篇文章主要介紹了在Java程序中運(yùn)用Redis緩存對(duì)象的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03

最新評(píng)論