【算法】【源码】Collections.shuffle 求给定集合的随机排列

1  问题描述

类似这种,现有数组1、2、3、4、5、6、7、8,编程实现对该数组随机排序的算法题,因为Collections类有一个随机排列集合的方法,所以我们直接看一下人家是怎么写的。

2  源码分析

// 主要的思想就是:从第n个元素开始跟它前边的1到n-1的随机其中一个元素进行交换
// 1、如果是列表的长度小于5或者列表实现是随机访问接口,就直接在列表中调整顺序
// 2、其他情况,把列表转成对象数组,把数组的存储的值的顺序打乱,然后再把数组转成列表。
// 可见源码中考虑代价问题了,列表小的时候直接调整的代价很小,如果列表很大的情况,直接在列表中调整会有效率问题,转成数组,数组查找的效率很高,调换代价就小很多了
private static final int SHUFFLE_THRESHOLD = 5;
public static void shuffle(List<?> list, Random rnd) {
        int size = list.size();
     // 长度小于5或者集合是可以随机访问的 就直接进行变换  随机访问这里可以理解为元素都在一块 比如数组
        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]);
            }
        }
    }
public static void swap(List<?> list, int i, int j) {
    final List l = list;
    // 利用集合的特性 巧妙转换 即set方法会返回当前下标的值
    l.set(i, l.set(j, l.get(i)));
}
private static void swap(Object[] arr, int i, int j) {
    Object tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

多看源码,多学习,大家加油!

 

posted @ 2023-02-10 07:18  酷酷-  阅读(48)  评论(0编辑  收藏  举报