Java实现List数据乱序写法(洗牌)

有两种写法:
一种是直接调用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;
    }

}

测试结果:


觉得内容还不错?打赏个钢镚鼓励鼓励!!👍