ArrayList 和 LinkedList 的實現與區別


(轉載請標明出處)

1、ArrayLis t的實現

2、LinkedLis t的實現

3、ArrayList 和 LinkedList 的區別

ArrayList 的實現:

 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++];
        }

    }
   ...      
}

 

LinkedList 的實現:

  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 和 LinkedList 的區別:

 結構上的區別:

   對於處理一列數據項,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的查詢效率低,但是增刪效率很高。適用於增刪動作的比較頻繁,查詢次數較少的元素管理集合。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM