学习排序算法时,为了用一个数组测试多个排序算法,排序完成后要进行打乱;
public static int[] shuffle(int [] arr) {
Random random=new Random();
int rand=0;
for (int i = 0; i < arr.length; i++) {
rand=random.nextInt(arr.length);
swap(arr,i,rand);
}
return arr;
}
不过我这样前面换过的元素还是在后面的交换范围里,不知道各处打乱的概率是不是相等的;
之后发现 java.util.Collections
中已经有实现了:
/*
反向遍历列表,从末尾到第二个元素,反复的将当前元素和一个随机选择的元素交换;
随机选择的范围为:第一个元素到当前元素(包括当前);
列表过长时,先转成数组打乱,再转回来,这样可以避免"线性访问"的列表(比如链表)重复遍历;
*/
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]);
}
}
}
public static void swap(List<?> list, int i, int j) {
// 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
final List l = list;
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;
}