有两种写法:
一种是直接调用jdk自身给我们提供的shuffle(洗牌)方法(推荐)。
一种是自己使用随机数对list进行排序实现。
shuffle方法
Collections.shuffle(list);
原理:遍历list数组,并随机与数组中的一个元素交换位置,时间复杂度O(n)。
源码如下:
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
// instead of using a raw type here, it's possible to capture
// the wildcard but it will require a call to a supplementary
// private method
ListIterator it = list.listIterator();
for (int i=0; i<arr.length; i++) {
it.next();
it.set(arr[i]);
}
}
}
随机数排序方法
list.sort((v1, v2) -> ThreadLocalRandom.current().nextInt(-1, 1));
原理:对list进行排序,只不过判定两个元素的排序前后使用了随机数。由于毕竟是排序,时间复杂度取决于排序算法,默认的排序算法是什么我忘记了,但是肯定大于O(n)(通过测试数据也能看出),所以不推荐。
两种方法的排序结果及耗时对比
测试代码如下:
public class Test {
public static void main(String[] args) {
run("使用shuffle", 5, () -> {
List<Integer> list = getList(10);
Collections.shuffle(list);
return list;
});
run("使用随机数排序", 5, () -> {
List<Integer> list = getList(10);
list.sort((v1, v2) -> ThreadLocalRandom.current().nextInt(-1, 1));
return list;
});
System.out.println("=============");
run("使用shuffle", 5, () -> {
List<Integer> list = getList(100);
Collections.shuffle(list);
return list;
});
run("使用随机数排序", 5, () -> {
List<Integer> list = getList(100);
list.sort((v1, v2) -> ThreadLocalRandom.current().nextInt(-1, 1));
return list;
});
System.out.println("=============");
}
/**
* 执行逻辑
*
* @param name
* @param times
* @param supplier
*/
public static void run(String name, int times, Supplier<List<?>> supplier) {
StopWatch watch = new StopWatch();
for (int i = 0; i <= times; i++) {
if (i == 0) {
//首次调用会比较慢,故排除第一次调用的耗时数据
supplier.get();
continue;
}
//统计耗时
watch.start();
List<?> list = supplier.get();
watch.stop();
System.out.printf("%s\t第%d次执行耗时%s结果:%s%n", name, i, watch.getLastTaskTimeNanos(), list);
}
System.out.printf("%s\t执行平均耗时%s%n", name, watch.getTotalTimeNanos() / times);
}
/**
* 获取一个list
*
* @return
*/
public static List<Integer> getList(int size) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < size; i++) {
list.add(i);
}
return list;
}
}
测试结果: