(一)結論
-
在尾部插入數據,數據量較小時LinkedList比較快,因為ArrayList要頻繁擴容,當數據量大時ArrayList比較快,因為ArrayList擴容是當前容量*1.5,大容量擴容一次就能提供很多空間,當ArrayList不需擴容時效率明顯比LinkedList高,因為直接數組元素賦值不需new Node
-
在首部插入數據,LinkedList較快,因為LinkedList遍歷插入位置花費時間很小,而ArrayList需要將原數組所有元素進行一次System.arraycopy
-
插入位置越往中間,LinkedList效率越低,因為它遍歷獲取插入位置是從兩頭往中間搜,index越往中間遍歷越久,因此ArrayList的插入效率可能會比LinkedList高
-
插入位置越往后,ArrayList效率越高,因為數組需要復制后移的數據少了,那么System.arraycopy就快了,因此在首部插入數據LinkedList效率比ArrayList高,尾部插入數據ArrayList效率比LinkedList高
-
LinkedList可以實現隊列,棧等數據結構,這是它的優勢
(二)在尾部插入數據
結論:當數據量越來越大時,ArrayList比LinkedList快
原因:當數據量大時,ArrayList每次擴容都能得到很大的新空間,解決了前期頻繁擴容的劣勢,而LinkedList雖然有尾指針,但是每次add都要將對象new成一個Node(而ArrayList直接數組對應位置元素賦值)
末尾插入源碼:
ArrayList:如果超出容量需要擴容,不需擴容時直接數組元素賦值
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
LinkedList:用傳入的值new一個Node對象,然后尾指針指向該新的Node
public void addLast(E e) { linkLast(e); }
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++; }
實驗對比:
public static void main(String[] argv) { LinkedList<Integer> linkedList = new LinkedList<Integer>(); ArrayList<Integer> arrayList = new ArrayList<Integer>(); Long start = System.nanoTime(); for (int i = 0; i < 100000; i++) { linkedList.addLast(i); } Long end = System.nanoTime(); System.out.println("LinkedList消耗時間:" + (end - start)); start = System.nanoTime(); for (int i = 0; i < 100000; i++) { arrayList.add(i); } end = System.nanoTime(); System.out.println("ArrayList消耗時間:" + (end - start)); }
(三)指定位置插入數據
(1)源碼對比
ArrayList:性能主要在於擴容和數組復制,而當size很大時擴容影響就會減少
- 判斷index是否合法
- 判斷是否需要擴容
- 數組復制,從index開始把后面的數組元素全部復制到相對后一位的位置,該方法是native方法而且是連續內存復制問題,因此性能影響也沒想象中的大
- 將element賦值給數組index元素
public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
LinkedList:性能主要在於遍歷鏈表查找index
- 判斷是否超過鏈表長度,超過則拋錯誤
- 如果是插入最后的位置直接使用linkLast方法而不必去遍歷查詢對應位置
- node方法尋找index所指向的Node,首先判斷index是否大於size/2,大於則從末尾往前找,小於則從0開始往后找
- 找到之后就是new一個node對象,設置指針的問題
public void add(int index, E element) { checkPositionIndex(index); if (index == size) linkLast(element); else linkBefore(element, node(index)); } 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; } } 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++; }
(2)首部插入實驗對比
結論:開頭插入,LinkedList比ArrayList快
(2)中間插入實驗對比
結論:中間插入LinkedList比ArrayList慢