05 - ArrayList or LinkedList? Improper use is a thousand times worse

Collection, as a container for storing data, is one of the most frequently used object types in our daily development. JDK provides developers with a series of collection types, which are implemented using different data structures. Therefore, different collection types have different usage scenarios.

Many students are often asked questions about collections during interviews. The more common ones are the difference between ArrayList and LinkedList.

I believe that most students can answer: "ArrayList is implemented based on arrays, and LinkedList is implemented based on linked lists."

When answering the usage scenario, I found that the answer of most students is: "When ArrayList and LinkedList add and delete elements, LinkedList is more efficient than ArrayList, and when traversing, ArrayList is more efficient than LinkedList .” Is this answer correct? Today's lecture will take you to verify.

1. Getting to know the List interface first

Before learning the List collection class, let's first look at the interface and class implementation relationship of the List collection class through this picture:

 We can see that ArrayList, Vector, and LinkedList collection classes inherit the AbstractList abstract class, while AbstractList implements the List interface and also inherits the AbstractCollection abstract class. ArrayList, Vector, and LinkedList realize their respective functions according to their own positioning.

ArrayList and Vector are implemented using arrays, and the implementation principles of the two are similar. LinkedList is implemented using a doubly linked list. That's all the basic foundation. Next, we will analyze the source code implementation of ArrayList and LinkedList in detail.

2. How is ArrayList implemented?

ArrayList is very commonly used, let's take a few test questions first, and check your understanding of ArrayList by yourself.

Question 1: When we look at the source code of the implementation class of ArrayList, you will find that the object array elementData is decorated with transient. We know that the transient keyword modifies the property, which means that the property will not be serialized. However, we have not seen the documentation Explains that ArrayList cannot be serialized, why?

Question 2: When we use ArrayList to add and delete, we are often reminded that "using ArrayList to add and delete operations will affect efficiency". Does that mean that the efficiency of ArrayList will definitely slow down in scenarios where a large number of new elements are added?

Question 3: If you were asked to use a for loop and an iterative loop to traverse an ArrayList, which method would you use? what is the reason?

If you don't have a comprehensive understanding of these tests, then let me re-understand ArrayList from the perspective of data structure, implementation principle and source code.

2.1, ArrayList implementation class

ArrayList implements the List interface and inherits the AbstractList abstract class. The bottom layer is implemented by an array, and realizes self-increasing and expanding the size of the array.

ArrayList also implements the Cloneable interface and the Serializable interface, so he can implement cloning and serialization.

ArrayList also implements the RandomAccess interface. You may be unfamiliar with this interface and don't know the specific use. Through the code, we can find that this interface is actually an empty interface, and nothing is implemented, so why does ArrayList implement it?

In fact, the RandomAccess interface is a flag interface, which marks "as long as the List class that implements this interface can achieve fast random access."

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

2.2. ArrayList property

The ArrayList attribute is mainly composed of array length size, object array elementData, and initialization capacity default_capacity, among which the default initialization capacity is 10.

// 默认初始化容量
private static final int DEFAULT_CAPACITY = 10;
// 对象数组
transient Object[] elementData; 
// 数组长度
private int size;

Judging from the ArrayList property, it is not modified by any multi-thread keyword, but elementData is modified by the keyword transient. This is the first test question I mentioned above: modifying the field with the transient keyword means that the property will not be serialized, but ArrayList actually implements the serialization interface. What is going on?

This has to start with "ArrayList is based on array implementation". Since the array of ArrayList is based on dynamic expansion, not all the allocated memory space stores data.

If the array is serialized using the external serialization method, the entire array will be serialized. In order to avoid the serialization of these memory spaces without storing data, ArrayList internally provides two private methods writeObject and readObject to complete serialization and deserialization by itself, thus saving space and time when serializing and deserializing arrays.

Therefore, using transient to modify the array is to prevent the object array from being serialized by other external methods.

2.3. ArrayList constructor

The ArrayList class implements three constructors. The first is to pass in an initialization value when creating an ArrayList object; the second is to create an empty array object by default; the third is to pass in a collection type for initialization.

When ArrayList adds new elements, if the stored elements exceed its existing size, it will calculate the size of the elements and then dynamically expand the capacity. The expansion of the array will cause the entire array to perform a memory copy. Therefore, when we initialize ArrayList, we can reasonably specify the initial size of the array through the first constructor, which will help reduce the number of expansions of the array and improve system performance.

public ArrayList(int initialCapacity) {
    // 初始化容量不为零时,将根据初始化值创建数组大小
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {// 初始化容量为零时,使用默认的空数组
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: " +
                initialCapacity);
    }
}

public ArrayList() {
    // 初始化默认为空数组
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

2.4, ArrayList new elements

There are two ways to add elements to ArrayList, one is to directly add elements to the end of the array, and the other is to add elements to any position.

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

public void add(int index, E element) {
    rangeCheckForAdd(index);

    ensureCapacityInternal(size + 1);  // Increments modCount!!
    System.arraycopy(elementData, index, elementData, index + 1,
            size - index);
    elementData[index] = element;
    size++;
}

The same thing between the two methods is that before adding elements, the capacity will be confirmed first. If the capacity is large enough, there is no need to expand the capacity; if the capacity is not large enough, the capacity will be expanded according to 1.5 times the size of the original array. Copy the array to a newly allocated memory address.

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

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

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 + (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);
}

Of course, there are also differences between the two methods. Adding an element to any position will cause all elements after that position to be rearranged, and adding an element to the end of the array will not happen without expansion. There is an element copy sorting process.

Here you can find the answer to the second test question. If we are clear about the size of the stored data during initialization, we can specify the size of the array when initializing the ArrayList, and when adding elements, only add elements at the end of the array, then the performance of ArrayList in the scene of a large number of new elements is not the same. It won't get worse, but it will perform better than other List collections.

2.5, ArrayList delete elements

The method of deleting an ArrayList is somewhat the same as the method of adding an element at any position. ArrayList needs to reorganize the array after each effective operation of deleting elements, and the higher the position of the deleted element, the greater the cost of array reorganization.

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

2.6. ArrayList traverses elements

Since ArrayList is implemented based on an array, it is very fast to get elements.

public E get(int index) {
    rangeCheck(index);

    return elementData(index);
}

E elementData(int index) {
    return (E) elementData[index];
}

3. How is LinkedList implemented?

Although both LinkedList and ArrayList are collections of List type, the implementation principle of LinkedList is quite different from that of ArrayList, and the usage scenarios are also different.

LinkedList is implemented based on the data structure of doubly linked list. LinkedList defines a Node structure, which contains 3 parts: element content item, front pointer prev and back pointer next. The code is as follows.

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

To sum up, LinkedList is a doubly linked list connected by Node structure objects. Before JDK1.7, LinkedList only contained a header attribute of the Entry structure, and an empty Entry was created by default as a header during initialization, and the front and back pointers pointed to itself, forming a circular doubly linked list.

After JDK1.7, LinkedList made a lot of changes and optimized the linked list. The Entry structure of the linked list is replaced by Node, and the internal composition basically remains unchanged, but the header attribute in the LinkedList is removed, and a first attribute of the Node structure and a last attribute of the Node structure are added. Doing so has the following advantages:

  • The first/last attribute can more clearly express the concept of the chain head and chain tail of the linked list;
  • The first/last method can save a new Entry when initializing the LinkedList;
  • The most important performance optimization of the first/last method is that the insertion and deletion operations at the chain head and chain tail are faster.

Here is the same as the explanation of ArrayList, I will give you an in-depth understanding of LinkedList from the perspectives of data structure, implementation principle and source code analysis.

3.1, LinkedList implementation class

The LinkedList class implements the List interface and the Deque interface, and inherits the AbstractSequentialList abstract class. LinkedList implements the characteristics of both the List type and the Queue type; LinkedList also implements the Cloneable and Serializable interfaces. Like ArrayList, it can implement cloning and serialization.

Because LinkedList stores data in memory addresses that are discontinuous, but uses pointers to locate discontinuous addresses, LinkedList does not support random fast access, and LinkedList cannot implement the RandomAccess interface.

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

3.2. LinkedList attribute

We mentioned the first/last attribute of the two important attributes of LinkedList earlier, in fact there is also a size attribute. We can see that these three properties are all modified by transient. The reason is very simple. When serializing, we will not only serialize the head and tail, so LinkedList also implements readObject and writeObject for serialization and deserialization.

transient int size = 0;
transient Node<E> first;
transient Node<E> last;

3.3, LinkedList new elements

The implementation of adding elements to LinkedList is very simple, but there are many ways to add elements. The default add (Ee) method is to add the added element to the end of the queue. First, replace the last element into a temporary variable to generate a new Node node object, and then point the last reference to the new node object. The previous last object The previous pointer points to the new node object.

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

LinkedList also has a method to add elements to any position. If we add an element to the middle of any two elements, the operation of adding an element will only change the front and back pointers of the front and back elements, and the pointer will point to the new element added, so compared to ArrayList For the addition operation, the performance advantage of LinkedList is obvious.

public void add(int index, E element) {
    checkPositionIndex(index);

    if (index == size)
        linkLast(element);
    else
        linkBefore(element, node(index));
}

void linkBefore(E e, Node<E> succ) {
    // assert succ != null;
    final Node<E> pred = succ.prev;
    final Node<E> newNode = new Node<>(pred, e, succ);
    succ.prev = newNode;
    if (pred == null)
        first = newNode;
    else
        pred.next = newNode;
    size++;
    modCount++;
}

3.4, LinkedList delete elements

In the operation of deleting elements in LinkedList, we must first find the element to be deleted by looping. If the position to be deleted is in the first half of the List, we will search from the front to the back; if the position is in the second half, we will search from the back to the front. .

In this way, it is very efficient whether you want to delete elements that are relatively front or behind, but if the List has a large number of elements and the removed elements are in the middle of the List, the efficiency will be relatively low.

3.5. LinkedList traverses elements

The implementation of LinkedList's element acquisition operation is basically similar to LinkedList's deletion element operation, and the corresponding element is found in a loop by dividing the front and back halves. But it is very inefficient to query elements in this way, especially in the case of for loop traversal, each loop will traverse half of the List.

So when traversing the LinkedList loop, we can use iterator to iterate the loop and get our elements directly without looking up the List through the loop.

4. Summary

Previously, we have deeply understood the implementation principles and characteristics of ArrayList and LinkedList from the perspective of source code implementation. If you can fully understand these contents, many related performance problems in practical applications will be solved.

Just like if someone still tells you now, "ArrayList and LinkedList are more efficient when adding and deleting elements, LinkedList is more efficient than ArrayList, and when traversing, ArrayList is more efficient than LinkedList", you will also agree ?

Now we might as well verify it through several sets of tests. Due to space limitations here, I will directly give the test results, and the corresponding test code can be viewed at the end.

4.1, ArrayList and LinkedList add element operation test

  • Add an element from the head position of the collection
  • Add an element from the middle of the collection
  • Add an element from the end of the collection

Test results (time spent):

  • ArrayList>LinkedList
  • ArrayList<LinkedList
  • ArrayList<LinkedList

Through this set of tests, we can know that the efficiency of adding elements to LinkedList is not necessarily higher than that of ArrayList.

Since ArrayList is implemented by an array, and the array is a continuous memory space, when adding elements to the head of the array, it is necessary to copy and rearrange the data after the head, so the efficiency is very low; while LinkedList is implemented based on a linked list. When adding an element, the position of the added element will be searched first through a loop. If the position to be added is in the first half of the List, it will be searched from front to back; if its position is in the second half, it will be searched from back to front. So LinkedList adding elements to the head is very efficient.

As can be seen from the above, when ArrayList adds elements to the middle of the array, some data also needs to be copied and rearranged, and the efficiency is not very high; LinkedList adds elements to the middle position, which is the lowest efficiency of adding elements, because near the middle position, adding elements The previous loop search is the operation that traverses the most elements.

In the operation of adding elements to the tail, we found that the efficiency of ArrayList is higher than that of LinkedList without expansion. This is because ArrayList does not need to copy and rearrange data when adding elements to the end, which is very efficient. Although LinkedList does not need to search for elements in a loop, LinkedList has more new objects and the process of changing pointers to objects, so the efficiency is lower than that of ArrayList.

To explain, here I am testing based on the fact that the ArrayList initialization capacity is sufficient, and the dynamic expansion of the array capacity is excluded. If there is a dynamic expansion, the efficiency of the ArrayList will also decrease.

4.2, ArrayList and LinkedList delete element operation test

  • removes an element from the head of the collection
  • Remove an element from the middle of the collection
  • removes an element from the end of the collection

Test results (time spent):

  • ArrayList>LinkedList
  • ArrayList<LinkedList
  • ArrayList<LinkedList

ArrayList and LinkedList delete element operation test results and add element operation test results are very close, this is the same principle, I will not repeat the explanation here.

3.ArrayList and LinkedList traverse element operation test

  • for(;;) loop
  • iterator loop

Test results (time spent):

  • ArrayList<LinkedList
  • ArrayList≈LinkedList

We can see that LinkedList's for loop performance is the worst, while ArrayList's for loop performance is the best.

This is because LinkedList is implemented based on a linked list. When using a for loop, each for loop will traverse half of the List, which seriously affects the efficiency of the traversal; ArrayList is implemented based on an array and implements the RandomAccess interface flag. It means that ArrayList can achieve fast random access, so the for loop is very efficient.

The iterative loop traversal of LinkedList and the iterative loop traversal of ArrayList have the same performance, and it is not too bad, so when traversing LinkedList, we should avoid using for loop traversal.

5. Thinking questions

Let's think about some issues that should be paid attention to in the delete operation of the ArrayList array through an example of using a for loop to traverse and delete the ArrayList array.

public static void main(String[] args)
{
    ArrayList<String> list = new ArrayList<String>();
    list.add("a");
    list.add("a");
    list.add("b");
    list.add("b");
    list.add("c");
    list.add("c");
    remove(list);// 删除指定的“b”元素

    for(int i=0; i<list.size(); i++)("c")()()(s : list)
    {
        System.out.println("element : " + s)list.get(i)
    }
}

From the above code, I defined an ArrayList array, added some elements, and then I deleted the specified elements through remove. Which of the following two sentences is correct?

Writing 1:

public static void remove(ArrayList<String> list)
{
    Iterator<String> it = list.iterator();

    while (it.hasNext()) {
        String str = it.next();

        if (str.equals("b")) {
            it.remove();
        }
    }

}

Writing 2:

public static void remove(ArrayList<String> list)
{
    for (String s : list)
    {
        if (s.equals("b"))
        {
            list.remove(s);
        }
    }
}

6. Test code

6.1、App.java

package com.demo.collection;

/**
 * ArrayList和ListedList集合性能测试对比
 * @author liuchao
 *
 */
public class App {
    public static void main(String[] args) {

        ArrayListTest.addFromHeaderTest(100000);
        LinkedListTest.addFromHeaderTest(100000);

        ArrayListTest.addFromMidTest(10000);
        LinkedListTest.addFromMidTest(10000);

        ArrayListTest.addFromTailTest(1000000);
        LinkedListTest.addFromTailTest(1000000);

        ArrayListTest.deleteFromHeaderTest(100000);
        LinkedListTest.deleteFromHeaderTest(100000);

        ArrayListTest.deleteFromMidTest(100000);
        LinkedListTest.deleteFromMidTest(100000);

        ArrayListTest.deleteFromTailTest(1000000);
        LinkedListTest.deleteFromTailTest(1000000);

        ArrayListTest.getByForTest(10000);
        LinkedListTest.getByForTest(10000);

        ArrayListTest.getByIteratorTest(100000);
        LinkedListTest.getByIteratorTest(100000);
    }
}

6.2、ArrayListTest.java

package com.demo.collection;

import java.util.ArrayList;
import java.util.Iterator;

public class ArrayListTest {

    /**
     *
     * @param DataNum
     */
    public static void addFromHeaderTest(int DataNum) {
        ArrayList<String> list = new ArrayList<String>(DataNum);
        int i = 0;

        long timeStart = System.currentTimeMillis();

        while (i < DataNum) {
            list.add(0, i + "aaavvv");
            i++;
        }
        long timeEnd = System.currentTimeMillis();

        System.out.println("ArrayList从集合头部位置新增元素花费的时间" + (timeEnd - timeStart));
    }

    /**
     *
     * @param DataNum
     */
    public static void addFromMidTest(int DataNum) {
        ArrayList<String> list = new ArrayList<String>(DataNum);
        int i = 0;

        long timeStart = System.currentTimeMillis();
        while (i < DataNum) {
            int temp = list.size();
            list.add(temp / 2 + "aaavvv");
            i++;
        }
        long timeEnd = System.currentTimeMillis();

        System.out.println("ArrayList从集合中间位置新增元素花费的时间" + (timeEnd - timeStart));
    }

    /**
     *
     * @param DataNum
     */
    public static void addFromTailTest(int DataNum) {
        ArrayList<String> list = new ArrayList<String>(DataNum);
        int i = 0;

        long timeStart = System.currentTimeMillis();

        while (i < DataNum) {
            list.add(i + "aaavvv");
            i++;
        }

        long timeEnd = System.currentTimeMillis();

        System.out.println("ArrayList从集合尾部位置新增元素花费的时间" + (timeEnd - timeStart));
    }

    /**
     *
     * @param DataNum
     */
    public static void deleteFromHeaderTest(int DataNum) {
        ArrayList<String> list = new ArrayList<String>();
        int i = 0;

        while (i < DataNum) {
            list.add(i + "aaavvv");
            i++;
        }
        long timeStart = System.currentTimeMillis();
        i = 0;

        while (i < DataNum) {
            list.remove(0);
            i++;
        }

        long timeEnd = System.currentTimeMillis();

        System.out.println("ArrayList从集合头部位置删除元素花费的时间" + (timeEnd - timeStart));
    }

    /**
     *
     * @param DataNum
     */
    public static void deleteFromMidTest(int DataNum) {
        ArrayList<String> list = new ArrayList<String>();
        int i = 0;
        while (i < DataNum) {
            list.add(i + "aaavvv");
            i++;
        }
        long timeStart = System.currentTimeMillis();
        i = 0;

        while (i < DataNum) {
            int temp = list.size();
            list.remove(temp / 2);
            i++;
        }

        long timeEnd = System.currentTimeMillis();

        System.out.println("ArrayList从集合中间位置删除元素花费的时间" + (timeEnd - timeStart));
    }

    /**
     *
     * @param DataNum
     */
    public static void deleteFromTailTest(int DataNum) {
        ArrayList<String> list = new ArrayList<String>();
        int i = 0;
        while (i < DataNum) {
            list.add(i + "aaavvv");
            i++;
        }

        long timeStart = System.currentTimeMillis();

        i = 0;

        while (i < DataNum) {
            int temp = list.size();
            list.remove(temp - 1);
            i++;

        }

        long timeEnd = System.currentTimeMillis();

        System.out.println("ArrayList从集合尾部位置删除元素花费的时间" + (timeEnd - timeStart));
    }

    /**
     *
     * @param DataNum
     */
    public static void getByForTest(int DataNum) {
        ArrayList<String> list = new ArrayList<String>();
        int i = 0;

        while (i < DataNum) {
            list.add(i + "aaavvv");
            i++;
        }
        long timeStart = System.currentTimeMillis();

        for (int j = 0; j < DataNum; j++) {
            list.get(j);
        }

        long timeEnd = System.currentTimeMillis();

        System.out.println("ArrayList for(;;)循环花费的时间" + (timeEnd - timeStart));
    }

    /**
     *
     * @param DataNum
     */
    public static void getByIteratorTest(int DataNum) {
        ArrayList<String> list = new ArrayList<String>();
        int i = 0;

        while (i < DataNum) {
            list.add(i + "aaavvv");
            i++;
        }
        long timeStart = System.currentTimeMillis();

        for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
            it.next();
        }

        long timeEnd = System.currentTimeMillis();

        System.out.println("ArrayList 迭代器迭代循环花费的时间" + (timeEnd - timeStart));
    }

}

6.3、LinkedListTest.java

package com.demo.collection;

import java.util.Iterator;
import java.util.LinkedList;

/**
 *
 * @author liuchao
 *
 */
public class LinkedListTest {

    /**
     *
     * @param DataNum
     */
    public static void addFromHeaderTest(int DataNum)
    {
        LinkedList<String> list=new LinkedList<String>();
        int i=0;
        long timeStart=System.currentTimeMillis();
        while(i<DataNum)
        {
            list.addFirst(i+"aaavvv");
            i++;
        }
        long timeEnd=System.currentTimeMillis();

        System.out.println("LinkedList从集合头部位置新增元素花费的时间"+(timeEnd-timeStart));
    }

    /**
     *
     * @param DataNum
     */
    public static void addFromMidTest(int DataNum)
    {
        LinkedList<String> list=new LinkedList<String>();
        int i=0;
        long timeStart=System.currentTimeMillis();
        while(i<DataNum)
        {
            int temp = list.size();
            list.add(temp/2, i+"aaavvv");
            i++;
        }
        long timeEnd=System.currentTimeMillis();

        System.out.println("LinkedList从集合中间位置新增元素花费的时间"+(timeEnd-timeStart));
    }

    /**
     *
     * @param DataNum
     */
    public static void addFromTailTest(int DataNum)
    {
        LinkedList<String> list=new LinkedList<String>();
        int i=0;
        long timeStart=System.currentTimeMillis();
        while(i<DataNum)
        {
            list.add(i+"aaavvv");
            i++;
        }
        long timeEnd=System.currentTimeMillis();

        System.out.println("LinkedList从集合尾部位置新增元素花费的时间"+(timeEnd-timeStart));
    }

    /**
     *
     * @param DataNum
     */
    public static void deleteFromHeaderTest(int DataNum)
    {
        LinkedList<String> list=new LinkedList<String>();
        int i=0;

        while(i<DataNum)
        {
            list.add(i+"aaavvv");
            i++;
        }
        long timeStart=System.currentTimeMillis();

        i=0;
        while(i<DataNum)
        {
            list.removeFirst();
            i++;
        }

        long timeEnd=System.currentTimeMillis();

        System.out.println("LinkedList从集合头部位置删除元素花费的时间"+(timeEnd-timeStart));
    }

    /**
     *
     * @param DataNum
     */
    public static void deleteFromMidTest(int DataNum)
    {
        LinkedList<String> list=new LinkedList<String>();

        int i=0;
        while(i<DataNum)
        {
            list.add(i+"aaavvv");
            i++;
        }

        long timeStart=System.currentTimeMillis();

        i=0;
        while(i<DataNum)
        {
            int temp = list.size();
            list.remove(temp/2);
            i++;
        }

        long timeEnd=System.currentTimeMillis();

        System.out.println("LinkedList从集合中间位置删除元素花费的时间"+(timeEnd-timeStart));
    }

    /**
     *
     * @param DataNum
     */
    public static void deleteFromTailTest(int DataNum)
    {
        LinkedList<String> list=new LinkedList<String>();
        int i=0;
        while(i<DataNum)
        {
            list.add(i+"aaavvv");
            i++;
        }

        long timeStart=System.currentTimeMillis();

        i=0;
        while(i<DataNum)
        {
            list.removeLast();
            i++;
        }


        long timeEnd=System.currentTimeMillis();

        System.out.println("LinkedList从集合尾部位置删除元素花费的时间"+(timeEnd-timeStart));
    }


    /**
     *
     * @param DataNum
     */
    public static void getByForTest(int DataNum) {
        LinkedList<String> list = new LinkedList<String>();
        int i = 0;

        while (i < DataNum) {
            list.add(i + "aaavvv");
            i++;
        }
        long timeStart = System.currentTimeMillis();

        for (int j=0; j < DataNum ; j++) {
            list.get(j);
        }

        long timeEnd = System.currentTimeMillis();

        System.out.println("LinkedList for(;;)循环花费的时间" + (timeEnd - timeStart));
    }

    /**
     *
     * @param DataNum
     */
    public static void getByIteratorTest(int DataNum) {
        LinkedList<String> list = new LinkedList<String>();
        int i = 0;

        while (i < DataNum) {
            list.add(i + "aaavvv");
            i++;
        }
        long timeStart = System.currentTimeMillis();

        for (Iterator<String> it=list.iterator(); it.hasNext();) {
            it.next();
        }

        long timeEnd = System.currentTimeMillis();

        System.out.println("LinkedList 迭代器迭代循环花费的时间" + (timeEnd - timeStart));
    }
}

Guess you like

Origin blog.csdn.net/qq_34272760/article/details/131899188