The difference between ArrayList, Vector, LinkedList

Four o'clock:

    1. Synchronization (thread safe or not)

    2. Data growth

    3.  Efficiency of finding, inserting, and deleting objects 

    4. Time and space

details as follows:

    1. Synchronization (thread safe or not)

        ArrayList and LinkedList are asynchronous, while Vestor is synchronous (multi-threaded). Of course, ArrayList and LinkedList can also be wrapped in some ways to make them synchronized, but the efficiency may be reduced.

        Implementation: The Synchronized keyword modifies most key methods, and the volatile keyword is not used

    2.  Data growth:

        Both ArrayList and Vector are stored in the array form of Objec;

         transient Object[] elementData;              // ArryList
         protected Object[] elementData;              // Vector

        Dynamic expansion: If the number of elements exceeds the current length of the internal array, they all need to expand the length of the internal array; Vector automatically doubles the length of the original array by default , ArrayList is 50% of the original , so in the end you get this Collections always take up more space than you actually need.

        The dynamic expansion of ArrayList is when adding elements:

     
public boolean add(E e) {
                 //Ensure the internal capacity (by judging, if it is enough, do not operate; if the capacity is not enough, expand the capacity to ensure the internal capacity)
            ensureCapacityInternal(size + 1);               // ①Increments modCount!!
            elementData[size++] = e;                        //②
             return true;
       }
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;                                //private static final int DEFAULT_CAPACITY = 10;
        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }
  
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); // If the actual storage array is an empty array, the minimum required capacity is the default capacity
 
        }

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0) //If the length of the array (elementData) is less than the minimum required capacity (minCapacity), expand the capacity
            grow(minCapacity);

    }
                                                                      //Extension algorithm
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1); // signed right shift one bit, so, 1.5 times
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity; //It is not enough to expand the capacity by 1.5 times, it is directly equal to it
        if (newCapacity - MAX_ARRAY_SIZE > 0) //If it is larger than the maximum space [0x7ffffff7]
            newCapacity = hugeCapacity(minCapacity);
       // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?                         //MAX_ARRAY_SIZE==[0x7ffffff7]
            Integer.MAX_VALUE :                                         //Integer.MAX_VALUE=[0x7fffffff]
            MAX_ARRAY_SIZE;
    }
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;         
//减去8是因为OutOfMemoryError:    Requested array size exceeds VM limit( Some VMs reserve some header words in an array.)

        Dynamic expansion of Vector :

 
 
public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }
public synchronized void ensureCapacity(int minCapacity) {
        if (minCapacity > 0) {
            modCount++;
            ensureCapacityHelper(minCapacity);
        }
    }

    /**
     * This implements the unsynchronized semantics of ensureCapacity.
     * Synchronized methods in this class can internally call this
     * method for ensuring capacity without incurring the cost of an
     * extra synchronization.
     *
     * @see #ensureCapacity(int)
     */
    private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }


  Each expansion is achieved by means of Arrays.copyOf(elementData, newCapacity).

  3. Find, insert, delete:

In ArrayList and Vector, the time to find an object         from the specified position (with index) , or to insert and delete an object at the end of the collection is the same, which can be expressed as O(1) . However, adding or removing elements elsewhere in the collection takes a linear increase in time: O(ni), where n is the number of elements in the collection and i is the index position at which the element was added or removed.

        In LinkedList, it takes the same amount of time to insert and delete an element anywhere in the collection — O(1) , but it is slower to find an element, O(i) , where i is the index position . 

4. Time and space

       a. Time complexity:

        The internal implementation of ArrayList is based on the underlying array of objects, so when it uses the get method to access any element in the list ( random access ), it is faster than LinkedList .

        The get method in LinkedList is to check sequentially from one end of the list to the other end . For LinkedList, there is no faster way to access a specific element in the list.

        b. Space complexity:

        There is a private inner class in LinkedList, defined as follows: 

     private static class Entry {   
             Object element;   
             Entry next;   
             Entry previous;   
          }   

        Each Entry object references an element in the list, as well as its previous and next elements in the LinkedList. A LinkedList object with 1000 elements will have 1000 Entry objects linked together, each corresponding to an element in the list. In this case, there will be a large space overhead in a LinkedList structure, because it needs to store the relevant information of these 1000 Entity objects. 

        ArrayList uses a built-in array to store elements. The starting capacity of this array is 10. When the array needs to grow, the new capacity is obtained by the following formula: new capacity=(old capacity*3)/2+1, that is to say Each time the capacity will increase by about 50%. This means that if you have an ArrayList object with a large number of elements, you will end up wasting a lot of space due to the way ArrayLists work. If there is not enough space for the new elements, the array will have to be reallocated so that new elements can be added. Reallocating the array will result in a dramatic drop in performance. If we know how many elements an ArrayList will have, we can specify the capacity through the constructor. We can also use the trimToSize method to get rid of the wasted space after the ArrayList is allocated.


Reference blog:

    1. https://blog.csdn.net/wangzff/article/details/7296648

    2. https://www.cnblogs.com/kuoAT/p/6771653.html

    3. https://blog.csdn.net/u010176014/article/details/52073339

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324828375&siteId=291194637