LinkedList是一個(gè)以雙向鏈表實(shí)現(xiàn)的List狂塘,它除了作為List使用,還可以作為隊(duì)列或者堆棧使用。
LinkedList介紹
LinkedList繼承關(guān)系
LinkedList簡介
-
LinkedList
是一個(gè)繼承于AbstractSequentialList
的雙向鏈表。它也可以被當(dāng)做堆棧、隊(duì)列或雙端隊(duì)列進(jìn)行使用思杯。 -
LinkedList
實(shí)現(xiàn)List
接口,能讓它進(jìn)行隊(duì)列操作。 -
LinkedList
實(shí)現(xiàn)Deque
接口色乾,即能將LinkedList
當(dāng)做雙端隊(duì)列使用誊册。 -
LinkedList
實(shí)現(xiàn)Cloneable
,即覆蓋了函數(shù)clone()
暖璧,能被克隆案怯。 -
LinkedList
實(shí)現(xiàn)了java.io.Serializable
接口,這意味著LinkedList
支持序列化澎办,能通過序列化去傳輸嘲碱。 -
LinkedList
中的操作不是線程安全的。
LinkedList源碼分析
AbstractSequentialList介紹
我們?cè)诳?code>LinkedList之前先簡單介紹下其父類AbstractSequentialList
局蚀。
AbstractSequentialList
繼承自AbstractList
麦锯,是List
接口的簡化版實(shí)現(xiàn)。
AbstractSequentialList
只支持按次序訪問(鏈表在內(nèi)存中不是按順序存放的琅绅,而是通過指針連在一起扶欣,為了訪問某一元素,必須從鏈頭開始順著指針才能找到某一個(gè)元素千扶。)料祠,不像AbstractList
可以隨機(jī)訪問。
想要實(shí)現(xiàn)一個(gè)支持次序訪問的List的話澎羞,只需要繼承這個(gè)類髓绽,并實(shí)現(xiàn)的指定的方法listIterator(int index)
和size()
。實(shí)現(xiàn)ListIterator
的hasNext()
煤痕、next()
梧宫、hasPrevious()
接谨、previous()
摆碉、previousIndex()
就可以獲得一個(gè)不可修改的列表,如果你想讓它可修改還需實(shí)現(xiàn)remove()
脓豪、set(E e)
巷帝、add(E e)
方法。
屬性
LinkedList
的主要屬性如下代碼所示:
//鏈表節(jié)點(diǎn)的個(gè)數(shù)
transient int size = 0;
//鏈表首節(jié)點(diǎn)
transient Node<E> first;
//鏈表尾節(jié)點(diǎn)
transient Node<E> last;
關(guān)于transient
關(guān)鍵字的最用可以查看我上次寫的ArrayList扫夜。
//內(nèi)部靜態(tài)類
private static class Node<E> {
//當(dāng)前節(jié)點(diǎn)元素值
E item;
//下一個(gè)節(jié)點(diǎn)
Node<E> next;
//上一個(gè)節(jié)點(diǎn)
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
構(gòu)造函數(shù)
無參構(gòu)造函數(shù)
如果不傳入?yún)?shù)楞泼,則使用默認(rèn)構(gòu)造方法創(chuàng)建LinkedList對(duì)象,如下:
public LinkedList() {
}
此時(shí)創(chuàng)建的是一個(gè)空的鏈表笤闯。
帶Collection對(duì)象的構(gòu)造函數(shù)
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
首先會(huì)調(diào)用無參數(shù)的構(gòu)造方法堕阔,然后調(diào)用addAll
方法將集合內(nèi)元素全部加入到鏈表中,addAll
方法我們后面會(huì)詳細(xì)的分析颗味。
從上述的倆個(gè)構(gòu)造方法可以看出LinkedList是一個(gè)無界鏈表超陆,不存在容量不足的問題。
添加元素
LinkedList主要提供addFirst
浦马、addLast
时呀、add
张漂、addAll
等方法來實(shí)現(xiàn)元素的添加。下面我們一一來看:
//在鏈表首部添加元素
public void addFirst(E e) {
linkFirst(e);
}
private void linkFirst(E e) {
//將內(nèi)部保存的首節(jié)點(diǎn)點(diǎn)賦值給f
final Node<E> f = first;
//創(chuàng)建新節(jié)點(diǎn)谨娜,新節(jié)點(diǎn)的next節(jié)點(diǎn)是當(dāng)前的首節(jié)點(diǎn)
final Node<E> newNode = new Node<>(null, e, f);
//把新節(jié)點(diǎn)作為新的首節(jié)點(diǎn)
first = newNode;
//判斷是否是第一個(gè)添加的元素
//如果是將新節(jié)點(diǎn)賦值給last
//如果不是把原首節(jié)點(diǎn)的prev設(shè)置為新節(jié)點(diǎn)
if (f == null)
last = newNode;
else
f.prev = newNode;
//更新鏈表節(jié)點(diǎn)個(gè)數(shù)
size++;
//將集合修改次數(shù)加1
modCount++;
}
//在鏈表尾部添加元素
public void addLast(E e) {
linkLast(e);
}
void linkLast(E e) {
//將內(nèi)部保存的尾節(jié)點(diǎn)賦值給l
final Node<E> l = last;
//創(chuàng)建新節(jié)點(diǎn)航攒,新節(jié)點(diǎn)的prev節(jié)點(diǎn)是當(dāng)前的尾節(jié)點(diǎn)
final Node<E> newNode = new Node<>(l, e, null);
//把新節(jié)點(diǎn)作為新的尾節(jié)點(diǎn)
last = newNode;
//判斷是否是第一個(gè)添加的元素
//如果是將新節(jié)點(diǎn)賦值給first
//如果不是把原首節(jié)點(diǎn)的next設(shè)置為新節(jié)點(diǎn)
if (l == null)
first = newNode;
else
l.next = newNode;
//更新鏈表節(jié)點(diǎn)個(gè)數(shù)
size++;
//將集合修改次數(shù)加1
modCount++;
}
//該方法和addLast方差不多,因?yàn)槭菬o界的趴梢,所以添加元素總是會(huì)成功
public boolean add(E e) {
linkLast(e);
return true;
}
//該方法和上面add方法的區(qū)別是漠畜,該方法可以指定位置插入元素
public void add(int index, E element) {
//判斷是否越界
checkPositionIndex(index);
//如果index等于鏈表節(jié)點(diǎn)個(gè)數(shù),就將元素添加到倆表尾部坞靶,否則調(diào)用linkBefore方法
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
//獲取指定位置的節(jié)點(diǎn)
Node<E> node(int index) {
//如果index小于size的一半盆驹,就從首節(jié)點(diǎn)開始遍歷,一直獲取x的下一個(gè)節(jié)點(diǎn)
//如果index大于或等于size的一半滩愁,就從尾節(jié)點(diǎn)開始遍歷躯喇,一直獲取x的上一個(gè)節(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;
}
}
//將元素插入到指定節(jié)點(diǎn)前
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
//拿到succ的上一節(jié)點(diǎn)
final Node<E> pred = succ.prev;
//創(chuàng)建新節(jié)點(diǎn)
final Node<E> newNode = new Node<>(pred, e, succ);
//將新節(jié)點(diǎn)作為succ的上一節(jié)點(diǎn)
succ.prev = newNode;
//判斷succ是否是首節(jié)點(diǎn)
//如果是將新節(jié)點(diǎn)作為新的首節(jié)點(diǎn)
//如果不是將新節(jié)點(diǎn)作為pred的下一節(jié)點(diǎn)
if (pred == null)
first = newNode;
else
pred.next = newNode;
//更新鏈表節(jié)點(diǎn)個(gè)數(shù)
size++;
//將集合修改次數(shù)加1
modCount++;
}
//將集合內(nèi)的元素依次插入index位置后
public boolean addAll(int index, Collection<? extends E> c) {
//判斷是否越界
checkPositionIndex(index);
//將集合轉(zhuǎn)換為數(shù)組
Object[] a = c.toArray();
int numNew = a.length;
//判斷數(shù)組長度是否為0,為0直接返回false
if (numNew == 0)
return false;
//pred上一個(gè)節(jié)點(diǎn)硝枉,succ當(dāng)前節(jié)點(diǎn)
Node<E> pred, succ;
//判斷index位置是否等于鏈表元素個(gè)數(shù)
//如果等于succ賦值為null廉丽,pred賦值為當(dāng)前鏈表尾節(jié)點(diǎn)last
//如果不等于succ賦值為index位置的節(jié)點(diǎn),pred賦值為succ的上一個(gè)節(jié)點(diǎn)
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index);
pred = succ.prev;
}
//循環(huán)數(shù)組
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
//創(chuàng)建新節(jié)點(diǎn)
Node<E> newNode = new Node<>(pred, e, null);
//如果上一個(gè)節(jié)點(diǎn)為null妻味,把新節(jié)點(diǎn)作為新的首節(jié)點(diǎn)正压,否則pred的下一個(gè)節(jié)點(diǎn)為新節(jié)點(diǎn)
if (pred == null)
first = newNode;
else
pred.next = newNode;
//把新節(jié)點(diǎn)賦值給上一個(gè)節(jié)點(diǎn)
pred = newNode;
}
//如果index位置的節(jié)點(diǎn)為null,把pred作業(yè)尾節(jié)點(diǎn)
//如果不為null责球,pred的下一節(jié)點(diǎn)為index位置的節(jié)點(diǎn)焦履,succ的上一節(jié)點(diǎn)為pred
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
//更新鏈表節(jié)點(diǎn)個(gè)數(shù)
size += numNew;
//將集合修改次數(shù)加1
modCount++;
//因?yàn)槭菬o界的,所以添加元素總是會(huì)成功
return true;
}
看到上面這么多種方式添加元素雏逾,其實(shí)本質(zhì)只是三種方式嘉裤,在鏈表的首部、尾部栖博、中間位置添加元素屑宠。如下圖所示:
在鏈表首尾添加元素很高效,在中間添加元素比較低效仇让,首先要找到插入位置的節(jié)點(diǎn)典奉,在修改前后節(jié)點(diǎn)的指針。
刪除元素
LinkedList提供了remove
丧叽、removeFirst
卫玖、removeLast
等方法刪除元素。
public boolean remove(Object o) {
//因?yàn)長inkedList允許存在null踊淳,所以需要進(jìn)行null判斷
if (o == null) {
//從首節(jié)點(diǎn)開始遍歷
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
//調(diào)用unlink方法刪除指定節(jié)點(diǎn)
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;
}
//刪除指定節(jié)點(diǎn)
E unlink(Node<E> x) {
//獲取x節(jié)點(diǎn)的元素假瞬,以及它上一個(gè)節(jié)點(diǎn),和下一個(gè)節(jié)點(diǎn)
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
//如果x的上一個(gè)節(jié)點(diǎn)為null,說明是首節(jié)點(diǎn)笨触,將x的下一個(gè)節(jié)點(diǎn)設(shè)置為新的首節(jié)點(diǎn)
//否則將x的上一節(jié)點(diǎn)設(shè)置為next懦傍,將x的上一節(jié)點(diǎn)設(shè)為null
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
//如果x的下一節(jié)點(diǎn)為null,說明是尾節(jié)點(diǎn)芦劣,將x的上一節(jié)點(diǎn)設(shè)置新的尾節(jié)點(diǎn)
//否則將x的上一節(jié)點(diǎn)設(shè)置x的上一節(jié)點(diǎn)粗俱,將x的下一節(jié)點(diǎn)設(shè)為null
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
//將x節(jié)點(diǎn)的元素值設(shè)為null,等待垃圾收集器收集
x.item = null;
//鏈表節(jié)點(diǎn)個(gè)數(shù)減1
size--;
//將集合修改次數(shù)加1
modCount++;
//返回刪除節(jié)點(diǎn)的元素值
return element;
}
//刪除指定位置的節(jié)點(diǎn)虚吟,其實(shí)和上面的方法差不多
//通過node方法獲得指定位置的節(jié)點(diǎn)寸认,再通過unlink方法刪除
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
//刪除首節(jié)點(diǎn)
public E remove() {
return removeFirst();
}
//刪除首節(jié)點(diǎn)
public E removeFirst() {
final Node<E> f = first;
//如果首節(jié)點(diǎn)為null,說明是空鏈表串慰,拋出異常
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
//刪除首節(jié)點(diǎn)
private E unlinkFirst(Node<E> f) {
//首節(jié)點(diǎn)的元素值
final E element = f.item;
//首節(jié)點(diǎn)的下一節(jié)點(diǎn)
final Node<E> next = f.next;
//將首節(jié)點(diǎn)的元素值和下一節(jié)點(diǎn)設(shè)為null偏塞,等待垃圾收集器收集
f.item = null;
f.next = null; // help GC
//將next設(shè)置為新的首節(jié)點(diǎn)
first = next;
//如果next為null,說明說明鏈表中只有一個(gè)節(jié)點(diǎn)邦鲫,把last也設(shè)為null
//否則把next的上一節(jié)點(diǎn)設(shè)為null
if (next == null)
last = null;
else
next.prev = null;
//鏈表節(jié)點(diǎn)個(gè)數(shù)減1
size--;
//將集合修改次數(shù)加1
modCount++;
//返回刪除節(jié)點(diǎn)的元素值
return element;
}
//刪除尾節(jié)點(diǎn)
public E removeLast() {
final Node<E> l = last;
//如果首節(jié)點(diǎn)為null灸叼,說明是空鏈表,拋出異常
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
private E unlinkLast(Node<E> l) {
//尾節(jié)點(diǎn)的元素值
final E element = l.item;
//尾節(jié)點(diǎn)的上一節(jié)點(diǎn)
final Node<E> prev = l.prev;
//將尾節(jié)點(diǎn)的元素值和上一節(jié)點(diǎn)設(shè)為null庆捺,等待垃圾收集器收集
l.item = null;
l.prev = null; // help GC
//將prev設(shè)置新的尾節(jié)點(diǎn)
last = prev;
//如果prev為null古今,說明說明鏈表中只有一個(gè)節(jié)點(diǎn),把first也設(shè)為null
//否則把prev的下一節(jié)點(diǎn)設(shè)為null
if (prev == null)
first = null;
else
prev.next = null;
//鏈表節(jié)點(diǎn)個(gè)數(shù)減1
size--;
//將集合修改次數(shù)加1
modCount++;
//返回刪除節(jié)點(diǎn)的元素值
return element;
}
刪除和添加一樣滔以,其實(shí)本質(zhì)只有三種方式捉腥,即刪除首部、尾部你画、中間節(jié)點(diǎn)抵碟。如下圖所示:
和添加一樣,首尾刪除很高效坏匪,刪除中間元素比較低效要先找到節(jié)點(diǎn)位置拟逮,再修改前后指針。
獲取元素
LinkedList提供了get
剥槐、getFirst
唱歧、getLast
等方法獲取節(jié)點(diǎn)元素值宪摧。
//獲取指定位置的元素值
public E get(int index) {
//判斷是否越界
checkElementIndex(index);
//直接調(diào)用node方法獲取指定位置的節(jié)點(diǎn)粒竖,并反回其元素值
return node(index).item;
}
//獲取鏈表首節(jié)點(diǎn)的元素值
public E getFirst() {
final Node<E> f = first;
//判斷是否是空鏈表,如果是拋出異常几于,否則直接返回首節(jié)點(diǎn)的元素值
if (f == null)
throw new NoSuchElementException();
return f.item;
}
//獲取鏈表尾節(jié)點(diǎn)的元素值
public E getLast() {
final Node<E> l = last;
//判斷是否是空鏈表蕊苗,如果是拋出異常,否則直接返回尾節(jié)點(diǎn)的元素值
if (l == null)
throw new NoSuchElementException();
return l.item;
}
更新指定位置節(jié)點(diǎn)的元素值
public E set(int index, E element) {
//判斷是否越界
checkElementIndex(index);
//指定位置的節(jié)點(diǎn)
Node<E> x = node(index);
E oldVal = x.item;
//設(shè)置新值
x.item = element;
//返回老值
return oldVal;
}
關(guān)于隊(duì)列的操作
LinkedList可以作為FIFO(First In First Out)的隊(duì)列沿彭,也就是先進(jìn)先出的隊(duì)列使用朽砰,以下是關(guān)于隊(duì)列的操作。
//獲取隊(duì)列的第一個(gè)元素,如果為null會(huì)返回null
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
//獲取隊(duì)列的第一個(gè)元素瞧柔,如果為null會(huì)拋出異常
public E element() {
return getFirst();
}
//獲取隊(duì)列的第一個(gè)元素漆弄,如果為null會(huì)返回null
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
//獲取隊(duì)列的第一個(gè)元素,如果為null會(huì)拋出異常
public E remove() {
return removeFirst();
}
//將元素添加到隊(duì)列尾部
public boolean offer(E e) {
return add(e);
}
關(guān)于雙端隊(duì)列的操作
雙端列隊(duì)可以作為棧使用造锅,棧的特性是LIFO(Last In First Out)撼唾,也就是后進(jìn)先出。所以作為棧使用也很簡單哥蔚,添加和刪除元素都只操作隊(duì)列的首節(jié)點(diǎn)即可倒谷。
//將元素添加到首部
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
//將元素添加到尾部
public boolean offerLast(E e) {
addLast(e);
return true;
}
//獲取首部的元素值
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
//獲取尾部的元素值
public E peekLast() {
final Node<E> l = last;
return (l == null) ? null : l.item;
}
//刪除首部,如果為null會(huì)返回null
public E pollFirst() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
//刪除尾部糙箍,如果為null會(huì)返回null
public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
}
//將元素添加到首部
public void push(E e) {
addFirst(e);
}
//刪除首部渤愁,如果為null會(huì)拋出異常
public E pop() {
return removeFirst();
}
//刪除鏈表中元素值等于o的第一個(gè)節(jié)點(diǎn),其實(shí)和remove方法是一樣的深夯,因?yàn)閮?nèi)部還是調(diào)用的remove方法
public boolean removeFirstOccurrence(Object o) {
return remove(o);
}
//刪除鏈表中元素值等于o的最后一個(gè)節(jié)點(diǎn)
public boolean removeLastOccurrence(Object o) {
//因?yàn)長inkedList允許存在null抖格,所以需要進(jìn)行null判斷
if (o == null) {
//和remove方法的區(qū)別它是從尾節(jié)點(diǎn)往前遍歷
for (Node<E> x = last; x != null; x = x.prev) {
if (x.item == null) {
//調(diào)用unlink方法刪除指定節(jié)點(diǎn)
unlink(x);
return true;
}
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
其他方法
//判斷元素是否存在于鏈表中
public boolean contains(Object o) {
return indexOf(o) != -1;
}
//從前往后查找返回節(jié)點(diǎn)元素值等于o的位置,不存在返回-1
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
//該方法和上面indexOf方法相反咕晋,它是從后往前查找返回節(jié)點(diǎn)元素值等于o的位置他挎,不存在返回-1
public int lastIndexOf(Object o) {
int index = size;
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (x.item == null)
return index;
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (o.equals(x.item))
return index;
}
}
return -1;
}
//克隆函數(shù),返回LinkedList的克隆對(duì)象
public Object clone() {
LinkedList<E> clone = superClone();
// 將新建LinkedList置于最初狀態(tài)
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
// 將鏈表中所有節(jié)點(diǎn)的數(shù)據(jù)都添加到克隆對(duì)象中
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item);
return clone;
}
//返回LinkedList節(jié)點(diǎn)單元素值的Object數(shù)組
public Object[] toArray() {
Object[] result = new Object[size];
int i = 0;
//將鏈表中所有節(jié)點(diǎn)的元素值添加到object數(shù)組中
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
return result;
}
// 返回LinkedList的模板數(shù)組捡需。所謂模板數(shù)組办桨,即可以將T設(shè)為任意的數(shù)據(jù)類型
public <T> T[] toArray(T[] a) {
//如果a的長度小于LinkedList節(jié)點(diǎn)個(gè)數(shù),說明a不能容納LinkedList的所有節(jié)點(diǎn)元素值
//則新建一個(gè)數(shù)組站辉,數(shù)組大小為LinkedList節(jié)點(diǎn)個(gè)數(shù)呢撞,并賦值給a
if (a.length < size)
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
int i = 0;
Object[] result = a;
// 將鏈表中所有節(jié)點(diǎn)的元素值都添加到數(shù)組a中
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
if (a.length > size)
a[size] = null;
return a;
}
//將LinkedList中的數(shù)據(jù)寫入到輸入流中,先寫容量饰剥,再寫數(shù)據(jù)
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out any hidden serialization magic
s.defaultWriteObject();
// Write out size
s.writeInt(size);
// Write out all elements in the proper order.
for (Node<E> x = first; x != null; x = x.next)
s.writeObject(x.item);
}
//從輸入流中讀取數(shù)據(jù)殊霞,一樣是先讀容量,再讀數(shù)據(jù)
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in any hidden serialization magic
s.defaultReadObject();
// Read in size
int size = s.readInt();
//從輸入流中將元素值逐個(gè)添加到鏈表中
// Read in all elements in the proper order.
for (int i = 0; i < size; i++)
linkLast((E)s.readObject());
}
總結(jié)
- LinkedList自己實(shí)現(xiàn)了序列化和反序列化汰蓉,因?yàn)樗鼘?shí)現(xiàn)了writeObject和readObject方法绷蹲。
- LinkedList是一個(gè)以雙向鏈表實(shí)現(xiàn)的List。
- LinkedList還是一個(gè)雙端隊(duì)列顾孽,具有隊(duì)列祝钢、雙端隊(duì)列、棧的特性若厚。
- LinkedList在首部和尾部添加拦英、刪除元素效率高效,在中間添加测秸、刪除元素效率較低疤估。
- LinkedList雖然實(shí)現(xiàn)了隨機(jī)訪問灾常,但是效率低效,不建議使用铃拇。
- LinkedList是線程不安全的钞瀑。
文章作者: leisurexi
新博客地址: https://leisurexi.github.io
許可協(xié)議: 署名-非商業(yè)性使用-禁止演繹 4.0 國際 轉(zhuǎn)載請(qǐng)保留原文鏈接及作者。