ArrayList 和 LinkedList 的區別(底層數據結構): 什麽時候使用arrayList,什麽時候使用LinkedList (一個小時)
阿新 • • 發佈:2018-01-24
link 技術分享 splay 直接 浪費 指針 個數 prev ech
1.ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。
2.對於隨機訪問get和set,ArrayList覺得優於LinkedList,因為LinkedList要移動指針。
3.對於新增和刪除操作add和remove,LinedList比較占優勢,因為ArrayList要移動數據。
ArrayList是實現了基於動態數組的數據結構,根據源碼來了解下為什麽隨機get/set快 add/remove慢
public class ArrayList<E> extends AbstractList<E> implementsadd,remove慢List<E>, RandomAccess, Cloneable, java.io.Serializable { transient Object[] elementData; //動態數組 public boolean add(E e) { // 檢查數組的大小是否足夠,如果不夠將創建一個尺寸擴大一倍新數組, //將原數組的數據拷貝到新數組中,原數組丟棄,這裏會很 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; returntrue; } private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(intminCapacity) { modCount++; if (minCapacity - elementData.length > 0) grow(minCapacity); } /** *尺寸不夠擴大創建新數組尺寸擴大一倍,數據拷貝到新數組,原數組丟棄 **/ private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; } }
以下兩點可以體現慢
1,擴容
ArrayList裏面維護了一個數組,add時:
檢查數組的大小是否足夠,如果不夠將創建一個尺寸擴大一倍新數組, 將原數組的數據拷貝到新數組中,原數組丟棄,這裏會很慢
調用數組方法:
Arrays.copyOf(elementData, newCapacity)
2,多個元素發生移動
remove時:
將指定索引的元素移除是通過數組移動調用
System.arraycopy(elementData, index+1, elementData, index,numMoved);
一次刪除會有多個元素發生移動如圖
同理,add(int,E)向一個指定的位置加元素也會發生多個元素移動,
get/set則直接從數組中根據索引取出元素
public E get(int index) { rangeCheck(index); return elementData(index); } public E set(int index, E element) { rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; } E elementData(int index) { return (E) elementData[index]; }get/set
數組在內存中是連續存儲的,所以它的索引速度非常快,而且賦值與修改元素也很簡單
一、數組 數組在內存中是連續存儲的,所以它的索引速度非常快,而且賦值與修改元素也很簡單。 1、一維數組 聲明一個數組: int[] array = new int[5]; 初始化一個數組: int[] array1 = new int[5] { 1, 3, 5, 7, 9 }; //定長 聲明並初始化: int[] array2 = { 1, 3, 5, 7, 9 }; //不定長 2、多維數組 int[,] numbers = new int[3, 2] { {1, 2}, {3, 4}, {5, 6} }; 但是數組存在一些不足的地方。在數組的兩個數據間插入數據是很麻煩的,而且在聲明數組的時候必須指定數組的長度,數組的長度過長,會造成內存浪費,
過短會造成數據溢出的錯誤。如果在聲明數組時我們不清楚數組的長度,就會變得很麻煩。 針對數組的這些缺點,.net中最先提供了ArrayList對象來克服這些缺點。
LinkedList基於鏈表的數據結構
每個元素都包含了 上一個和下一個元素的引用,所以add/remove 只會影響到上一個和下一個元素,
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable { 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++; } public E remove() { return removeFirst(); } 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; } }add/remove
鏈表
刪除時只要改變下,周圍2個元素的引用
linkedList get/set就慢了
get(int) 傳入索引與 size的1/2比較,大於一半則從最後一個元素開始遍歷挨個查找,
小於一半則從第一個元素開始遍歷挨個查找
public E get(int index) { checkElementIndex(index); return node(index).item; } 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; } } public E set(int index, E element) { checkElementIndex(index); Node<E> x = node(index); E oldVal = x.item; x.item = element; return oldVal; }get/set
ArrayList 和 LinkedList 的區別(底層數據結構): 什麽時候使用arrayList,什麽時候使用LinkedList (一個小時)