简体   繁体   English

Java ArrayList与LinkedList的性能,仅与创建/插入和排序有关

[英]Performance on Java ArrayList vs LinkedList, pertaining to only Creation/Insertion and sorting

Consider the following code: 考虑以下代码:

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

public class testSortingSpeed {
    public static final int TOTAL_NUMBER = 10000000;

    public static void main(String[] args) {
        System.out.println("Creating ArrayList:");
        List<Pair<Integer, Integer>> a = new ArrayList<>();
        long start = System.currentTimeMillis();
        for (int i = 0; i < TOTAL_NUMBER; i++) {
            Pair<Integer, Integer> p = new Pair<>(
                (int ) Math.random() * TOTAL_NUMBER,
                (int ) Math.random() * TOTAL_NUMBER);
            a.add(p);
        }
        long end = System.currentTimeMillis();
        System.out.println("Time Elapsed = " + ((end - start) / 1000.0) + " seconds");
        System.out.println();

        System.out.println("Creating LinkedList:");
        List<Pair<Integer, Integer>> b = new LinkedList<>();
        start = System.currentTimeMillis();
        for (int i = 0; i < TOTAL_NUMBER; i++) {
            Pair<Integer, Integer> p = new Pair<>(
                (int ) Math.random() * TOTAL_NUMBER,
                (int ) Math.random() * TOTAL_NUMBER);
            b.add(p);
        }
        end = System.currentTimeMillis();
        System.out.println("Time Elapsed = " + ((end - start) / 1000.0) + " seconds");
        System.out.println();

        System.out.println("Sorting ArrayList:");
        start = System.currentTimeMillis();
        Collections.sort(a, Pair.LEXICOGRAPHIC_ORDER);
        end = System.currentTimeMillis();
        System.out.println("Time Elapsed = " + ((end - start) / 1000.0) + " seconds");
        System.out.println();

        System.out.println("Sorting LinkedList:");
        start = System.currentTimeMillis();
        Collections.sort(b, Pair.LEXICOGRAPHIC_ORDER);
        end = System.currentTimeMillis();
        System.out.println("Time Elapsed = " + ((end - start) / 1000.0) + " seconds");
        System.out.println();
    }
}

where Pair is a custom defined data structure. 其中Pair是一个自定义的数据结构。

Pair<F, S> { F first; S second; }

The output of the above program: Creating ArrayList: Time Elapsed = 0.885 seconds 上面程序的输出:创建ArrayList:经过的时间= 0.885秒

Creating LinkedList: Time Elapsed = 9.617 seconds 创建LinkedList:经过的时间= 9.617秒

Sorting ArrayList: Time Elapsed = 0.128 seconds 排序ArrayList:经过的时间= 0.128秒

Sorting LinkedList: Time Elapsed = 0.351 seconds 排序LinkedList:经过的时间= 0.351秒

I am a bit baffled, cos intuitively, LinkedList creation should be better than ArrayList. 我有点困惑,从直觉上来说,LinkedList的创建应该比ArrayList更好。

For sorting, that's kinda expected, as it says in api: https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html that Collections.sort dumps the list to an ArrayList, sort it, and convert it back to original list type (not sure about this) 对于排序,这有点像在api中所说的那样: https : //docs.oracle.com/javase/8/docs/api/java/util/Collections.html Collections.sort将列表转储到ArrayList中,进行排序并将其转换回原始列表类型(对此不确定)

and I guess there is probably optimization if the original list type is ArrayList. 如果原始列表类型是ArrayList,我想可能有优化。

This will be implementation specific, depending on how ArrayList grows on your platform... But on most platforms, it multiplies its size by a factor of 1.5 every time it's capacity is reached. 这将是特定于实现的,具体取决于ArrayList在平台上的增长方式。但是在大多数平台上,每次达到容量时,它的大小就会乘以1.5。

Here's the code from JDK 1.8: 这是JDK 1.8中的代码:

/**
 * Increases the capacity to ensure that it can hold at least the
 * number of elements specified by the minimum capacity argument.
 *
 * @param minCapacity the desired minimum capacity
 */
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);
}

This method will be called 36 times if you're adding ten million objects into an empty ArrayList, which has a default initial capacity of 10. I've done some profiling on grow() and Arrays.copyOf(), and they're very fast, even for large arrays. 如果将一千万个对象添加到一个空的ArrayList中,该方法将被调用36次,该ArrayList的默认初始容量为10。我已经对grow()和Arrays.copyOf()进行了分析,即使对于大型阵列,速度也非常快。

LinkedList, on the other hand, needs to allocate a new Node object for every element added to it--ten million times. 另一方面,LinkedList需要为添加到它的每个元素(一千万次)分配一个新的Node对象。 That's why LinkedList is slower in this case. 这就是为什么LinkedList在这种情况下速度较慢的原因。 It's much faster when you need to insert or remove elements somewhere near the beginning or middle of the list. 它的速度更快,当你需要插入或删除的地方靠近列表的开头或中间元素。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM