【算法】【源码】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; }
多看源码,多学习,大家加油!