目錄
參考書:《很好-Java程序性能優化.pdf》
List有三種:ArrayList、Vector和LinkedList.我們只討論Arrylist和LinkedList
以下研究都是在jdk1.7
6.1.ArrayList
討論:組成,初始化大小,怎麼擴容,怎麼插入、刪除
1.組成:
內部封裝了對數組的操作,對他進行添加、刪除、插入都是對數組的操作.
代碼:
public class ArrayList<E> { private static final int DEFAULT_CAPACITY = 10;//默認容量 private transient Object[] elementData;//數組 private int size;//數組實際存儲大小,並不是數組的大小 } |
原文:https://blog.csdn.net/lan861698789/article/details/81323634
2.怎麼擴容
如果不指定容量,那麼默認容量大小就是10。
每次對數組進行添加、插入都需要判斷 內部數組是否有足夠的空間,沒有則擴容。
擴容大小爲原來大小的1.5倍。
以添加爲例,代碼:
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } private void ensureExplicitCapacity(int minCapacity) { modCount++; if (minCapacity - elementData.length > 0) {//判斷是否需要擴容 int oldCapacity = elementData.length;//現在容量大小 int newCapacity = oldCapacity + (oldCapacity >> 1);//擴容原來容量的1.5倍 if (newCapacity - minCapacity < 0) //如果擴容後還是不能滿足,則當前容量設置爲 需要插入的大小 newCapacity = minCapacity;
elementData = Arrays.copyOf(elementData, newCapacity);//數組的擴容 } } |
合理的數組大小,有助於減少數組擴容的次數,從而提高系統性能.
原文:https://blog.csdn.net/lan861698789/article/details/81323634
3.新增
新增是加到數組的最後一個。
代碼:
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } |
原理:
a.擴容一個長度
b.將數組的最後一位賦值爲要增加的元素
原文:https://blog.csdn.net/lan861698789/article/details/81323634
4.插入
任意位置添加元素.
代碼:
public void add(int index, E element) { ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } |
原理:
a.擴容一個長度
b.把從插入位置的元素往後移一位
c.賦值要插入的元素
原文:https://blog.csdn.net/lan861698789/article/details/81323634
5、插入數組
和插入一個元素區別不大。
代碼:
public boolean addAll(int index, Collection<? extends E> c) { Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // Increments modCount
int numMoved = size - index; if (numMoved > 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved);//部分元素整體右移
System.arraycopy(a, 0, elementData, index, numNew);//複製要插入的元素數組 size += numNew; return numNew != 0; }
|
原理:
原文:https://blog.csdn.net/lan861698789/article/details/81323634
6、刪除
代碼:
public E remove(int 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; } |
原文:https://blog.csdn.net/lan861698789/article/details/81323634
6.2.LinkedList
討論:組成,初始化大小,怎麼擴容,怎麼插入、刪除
1.組成:
使用了雙向鏈表的數據結構。
不需要擴容。
linkedlist只會存這個容器的長度,首、尾元素。
然後每個元素裏面包含了該元素的當前值,前一個元素,後一個元素。
代碼
public class LinkedList<E> { transient int size = 0; transient Node<E> first;//頭節點 transient Node<E> last;//尾節點 }
private static class Node<E> { E item;//當前值 Node<E> next;//指向前面一個元素 Node<E> prev;//指向後面的元素
Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } } |
原文:https://blog.csdn.net/lan861698789/article/details/81323634
原文:https://blog.csdn.net/lan861698789/article/details/81323634
2.新增
新增是往最後插的。
代碼:
void linkLast(E e) { final Node<E> l = last;//原來的last賦值 final Node<E> newNode = new Node<>(l, e, null);//構建新節點,這裏把原來的last賦值給了新節點的pre last = newNode;//last賦值 l.next = newNode; size++; modCount++; } |
原理:
構建新節點,把新節點的prev指向原來的最後一個節點;
把原來最後一個節點的next指向新節點。
原文:https://blog.csdn.net/lan861698789/article/details/81323634
3.插入
插入任一點
代碼:
public void add(int index, E element) { linkBefore(element, node(index)); } //找出該位置的節點值 Node<E> node(int index) { //做了一個size判斷。是從頭循環開始找,還是從尾循環開始找 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) { final Node<E> pred = succ.prev; final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode; pred.next = newNode; size++; modCount++; } |
原理:
從首or尾節點循環遍歷到該index位置,找出要插入位置的值
再進行 各種賦值。
原文:https://blog.csdn.net/lan861698789/article/details/81323634
4.刪除
刪除任意位置的值
代碼:
public E remove(int index) { return unlink(node(index)); } E unlink(Node<E> x) { // assert x != null; final E element = x.item; final Node<E> prev = x.prev; final Node<E> next = x.next; //前面元素的next 重新賦值 prev.next = next; x.prev = null; //後面元素的prev 重新賦值 next.prev = prev; x.next = null; //當前元素置爲空 x.item = null; size--; modCount++; return element; } |
原理:
從首or尾節點循環遍歷到該index位置,找出要插入位置的值
再進行 各種賦值。
原文:https://blog.csdn.net/lan861698789/article/details/81323634
6.3兩種List使用對比
如果是經常要進行任意位置的插入,建議使用linkedList;不使用arrayList,是因爲要頻繁擴容。
如果是經常要進行任意位置的查找,建議使用arrayList;不使用linkedlist,是因爲要循環查找。