是否更快地随机播放列表或生成它?

时间:2013-08-29 03:52:58

标签: java list sorting random shuffle

为了在分析排序算法中使用,我希望ArrayList<Integer>具有一百万美元整数。整数的界限无关紧要:[0,MAX_VALUE],[MIN_VALUEMAX_VALUE]等都很好,但我确实希望它们广泛分布。< / p>

我注意到当我使用这段代码时:

for (int i=0; i<1_000_000; i++) {
    list.add(i);
}
Collections.shuffle(list);
mergeSorter.sort(list);

shuffle调用执行大约需要十秒钟,而合并排序只需要2毫秒。

因此,我的问题:随机生成这些数字(list.add((int) (Math.random() * 1_000_000)))比使用shuffle更快,为什么?

(我自己会对此进行分析,但我的家用硬件不足以对此进行测试。另外,我想要一个概念/理论解释。)

2 个答案:

答案 0 :(得分:4)

Collections.shuffle()使用了Random

public static void shuffle(List<?> list, Random rnd) {
    int size = list.size();
    if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
        for (int i=size; i>1; i--)
            swap(list, i-1, rnd.nextInt(i));
    } else {
        Object arr[] = list.toArray();

        // Shuffle array
        for (int i=size; i>1; i--)
            swap(arr, i-1, rnd.nextInt(i));

        // Dump array back into list
        ListIterator it = list.listIterator();
        for (int i=0; i<arr.length; i++) {
            it.next();
            it.set(arr[i]);
        }
    }
}

仔细观察,会执行两个循环。

  • 一个用于创建新数组
  • 一个用于更新列表。

如果您自己执行此操作,则可以取消第二个循环,并让 GC 收集列表。如果你有一个数组开始,你甚至不需要创建一个新副本。

所以是的,自己动手会提高性能,但时间复杂度仍然是 O(n)

答案 1 :(得分:3)

  

随机生成这些数字(list.add((int) (Math.random() * 1_000_000)))比使用shuffle更快,为什么?

生成这样的数字会更快,但你会得到不同的结果!

  • 如果您将数字0到N-1的列表混洗,则会得到一个没有重复的列表。

  • 如果您在0到N-1范围内生成N个随机数的丢失,则可能会获得包含重复项的列表。


如果生成N个随机数就行,那肯定会比洗牌更快。从代码中可以看出,shuffle的最佳案例版本涉及生成N个随机数并执行N个交换。


  

shuffle调用大约需要十秒钟才能执行,而merge sort只需要2毫秒。

我不确定你为什么要比较shuffle和mergesort(或者你正在使用的合并排序器!)但我怀疑这种差异更多地与你编写基准测试的方式有关。 (看起来你可能没有允许JVM预热效果。)