(轉載請標明出處)
1、MyArrayList將保持基礎數組,數組的容量。以及存儲在MyArrayList中的當前項數。
2、MyArrayList將提供一種機制以改變基礎數組的容量。通過或者一個新數組,將老數組拷貝到新數組中改變數組的容量,允許虛擬機回收老數組。
3、MyArrayList將提供get和set的實現。
4、MyArrayList將提供基本的例程(Routine,系統對外提供的功能接口的集合),如size,isEmpty和clear,他們是典型的單行程序;還提供remove,以及兩種不同版本的add。如果數組的大小和容量相同,那么這兩個add例程將增加容量 。
5、MyArrayList將提供一個實現Iterator接口的類。這個類將存儲迭代序列中的下一項的下標,並提供next,hasNext和和remove等方法的實現。MyArrayList的迭代器方法直接返回實現Iterator接口的該類的新構造的實例。
public class MyArrayList<T> implements Iterator<T> { private static final int DEFAULT_CAPACITY = 10; private int theSize; private T[] theItems; public MyArrayList() { doClear(); } public void clear(){ doClear(); } private void doClear(){ theSize = 0; ensureCapacity(DEFAULT_CAPACITY); } public int size(){ return theSize; } public void ensureCapacity(int newCapacity){ if(newCapacity < theSize){ return; } T[] old = theItems; theItems = (T[]) new Object[newCapacity]; for(int i = 0; i < size(); i++){ theItems[i] = old[i]; } } public boolean add(T x){ add(size(),x); return true; } public void add(int idx, T x){ if(theItems.length == size()){ ensureCapacity(size() * 2 + 1); } for(int i = theSize; i > idx; i--){ theItems[i] = theItems[i-1]; theItems[idx] = x; } theSize++; } public T remove(int idx){ T removeItem = theItems[idx]; for(int i = idx; i < size() - 1; i++){ theItems[i] = theItems[i + 1]; } theSize--; return removeItem; } public java.util.Iterator<T> iterator(){ return new ArrayListIterator<T>(this); } private static class ArrayListIterator<T> implements Iterator<T>{ private int current = 0; private MyArrayList<T> theList; public ArrayListIterator(MyArrayList<T> list) { theList = list; } @Override public boolean hasNext() { return current<theList.size(); } @Override public T next() { return theList.theItems[current++]; } } ... }
1、MyLinkedList 類本身,包含到兩端的鏈,表的大下以及一些方法。
2.、Node類,他可能是一個私有的嵌套類。一個節點包含數據以及到前一個節點的鏈和到下一個節點的鏈,還有一些適當的構造方法。
3.、LinkedListIterator 類,該類抽象了位置的概念,是一個私有類,並實現接口Iterator。它提供了方法next,hasNext,remove的實現。
public class MyLinkedList<T> implements Iterator<T> { private int theSize; private int modCount = 0; private Node<T> beginMarker; private Node<T> endMarker; private static class Node<T>{ public T data; public Node<T> prev; public Node<T> next; public Node(T d, Node<T> p,Node<T> n){ data = d; prev = p; next = n; } } public MyLinkedList(){ doClear(); } public void clear(){ doClear(); } private void doClear() { beginMarker = new Node<T>(null,null,null); endMarker = new Node<T>(null,beginMarker,null); beginMarker.next = endMarker; theSize = 0; modCount++; } public int size(){ return theSize; } public boolean isEmpty(){ return size() == 0; } public boolean add(T x){ add(size(),x); return true; } private Node<T> getNode(int idx){ return getNode(idx,0,size()-1); } private Node<T> getNode(int idx, int lower, int upper ){ Node<T> p; if(idx < lower || idx > upper){ throw new IndexOutOfBoundsException(); } if(idx < size()/2 ){ p=beginMarker.next; for(int i= 0; i < idx; i++){ p = p.next; } }else{ p=endMarker; for(int i = size();i > idx; i--){ p = p.prev; } } return p; } public void add(int idx, T x){ addBefore(getNode(idx,0,size()),x); } public T get(int idx){ return getNode(idx).data; } public T set(int idx, T newVal){ Node<T> p = getNode(idx); T oldVal = p.data; p.data = newVal; return oldVal; } public T remove(int idx){ return remove(getNode(idx)); } private void addBefore(Node<T> p, T x){ Node<T> newNode = new Node<T>(x,p.prev,p); newNode.prev.next = newNode; p.prev = newNode; theSize++; modCount++; } private T remove(Node<T> p){ p.next.prev = p.prev; p.prev.next = p.next; theSize--; modCount++; return p.data; } public java.util.Iterator<T> iterator(){ return new LinkedListIterator(); } private class LinkedListIterator implements Iterator<T>{ private Node<T> current = beginMarker.next; private int expectedModCount = modCount; private boolean okToRemove = false; @Override public boolean hasNext() { return current != endMarker; } @Override public T next() { if(modCount != expectedModCount){ throw new java.util.ConcurrentModificationException(); } if(!hasNext()){ throw new java.util.NoSuchElementException(); } T nextItem = current.data; okToRemove = true; return nextItem; } public void remove(){ if(modCount != expectedModCount){ throw new java.util.ConcurrentModificationException(); } if(!okToRemove){ throw new IllegalStateException(); } MyLinkedList.this.remove(current.prev); expectedModCount++; okToRemove = false; } }
... }
結構上的區別:
對於處理一列數據項,ArrayList 的內部實現是基於內部數組Object[],所以從概念上講,它更像數組,但 LinkedList 的內部實現是基於一組連接的記錄,所以,它更像一個鏈表結構;ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。
性能上的區別:
查詢:
二分查找法使用的隨機訪問(random access)策略,而LinkedList是不支持快速的隨機訪問的(訪問鏈表中的某個元素時,就必須從鏈表的一端開始沿着連接方向一個一個元素地去查找,直到找到所需的元素為止)。對一個LinkedList做隨機訪問所消耗的時間與這個表的大小是成比例的。而相應的,在ArrayList中進行隨機訪問所消耗的時間是固定的。
增刪:
1、若只對單條數據插入或刪除,ArrayList的速度反而優於LinkedList。
2、若是批量插入或刪除數據:
ArrayList 是基於數組實現的,而數組是一塊連續的內存空間,當在表的前面或中間插入或刪除元素時,所有已經存在的元素都會后移,這就意味着數據移動和復制上的開銷,當在表的后面插入或刪除元素時,ArrayList和LinkedList數據量小時速度相差無幾,但數據量較大時ArrayList的速度快。在末尾插入或刪除數據,arraylist的速度比linkedlist的速度反而要快。注:其實在前方插入時,ArrayList可以使用后方插入,最后再使用Collections.reverse()方法反轉,速度比LinkedList快。
LinkedList 插入或刪除數據則只是簡單的未這個元素分配一個記錄,然后調整兩個連接,在表的尾端插入數據與在任意位置插入數據是一樣的,不會因為插入的位置靠前而導致插入的方法性能降低。
遍歷列表:最簡便的ForEach循環並沒有很好的性能表現,綜合性能不如普通的迭代器,而是用for循環通過隨機訪問遍歷列表時,ArrayList表項很好,但是LinkedList的表現卻無法讓人接受,甚至沒有辦法等待程序的結束。這是因為對LinkedList進行隨機訪問時,總會進行一次列表的遍歷操作。性能非常差,應避免使用。
性能開銷:
在LinkedList中有一個私有的內部類,
private static class Node<T>{ public T data; public Node<T> prev; public Node<T> next; public Node(T d, Node<T> p,Node<T> n){ data = d; prev = p; next = n; } }
每個Node對象 reference列表中的一個元素,同時還有在LinkedList中它的上一個元素和下一個元素。一個有1000個元素的LinkedList對象將 有1000個鏈接在一起的Node對象,每個對象都對應於列表中的一個元素。這樣的話,在一個LinkedList結構中將有一個很大的空間開銷,因為 它要存儲這1000個Node對象的相關信息。
ArrayList使用一個內置的數組來存儲元素,這個數組的起始容量是10.當數組需要增長時,新的容量按 如下公式獲得:新容量=(舊容量*3)/2+1,也就是說每一次容量大概會增長50%。這就意味着,如果你有一個包含大量元素的ArrayList對象, 那么最終將有很大的空間會被浪費掉,這個浪費是由ArrayList的工作方式本身造成的。如果沒有足夠的空間來存放新的元素,數組將不得不被重新進行分 配以便能夠增加新的元素。對數組進行重新分配,將會導致性能急劇下降。如果我們知道一個ArrayList將會有多少個元素,我們可以通過構造方法來指定容量。我們還可以通過trimToSize方法在ArrayList分配完畢之后去掉浪費掉的空間。
總結:
1、在ArrayList的 中間插入或刪除一個元素意味着這個列表中剩余的元素都會被移動;而在LinkedList的中間插入或刪除一個元素的開銷是固定的。
2、ArrayList的空間浪費主要體現在在list列表的結尾預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗相當的空間。
3、LinkedList不 支持高效的隨機元素訪問。
4、ArrayList的查詢效率比較高,增刪動作的效率比較差,適用於查詢比較頻繁,增刪動作較少的元素管理的集合。
LinkedList的查詢效率低,但是增刪效率很高。適用於增刪動作的比較頻繁,查詢次數較少的元素管理集合。
