FisherYates shuffle 基本思想(Knuth shuffle):
Чтобы перетасовать массив a из n элементов (индексы 0..n-1):
для i от n − 1 до 1 сделать
j ← случайное целое число с 0 ≤ j ≤ i
поменять местами a[j] и a[i]
Формат JDK:
/**
* Перемещает каждый элемент списка на случайную новую позицию в списке.
* с использованием указанного генератора случайных чисел.
*
* список @param
* Список для перетасовки
* @param случайный
* генератор случайных чисел
*
* @throws UnsupportedOperationException
* при замене элемента в Списке не поддерживается
*/
@SuppressWarnings («не отмечено»)
public static void shuffle(List<?> list, Random random) {
if (!(список экземпляров RandomAccess)) {
Массив Object[] = list.toArray();
for (int i = array.length - 1; i > 0; i--) {
int index = random.nextInt(i + 1);
если (индекс < 0) {
индекс = -индекс;
}
Температура объекта = массив[i];
массив[i] = массив[индекс];
массив [индекс] = температура;
}
интервал я = 0;
ListIterator<Object> it = (ListIterator<Object>) список
.listIterator();
в то время как (it.hasNext()) {
это.следующий();
it.set(массив[i++]);
}
} еще {
Список<Объект> rawList = (Список<Объект>) список;
for (int i = rawList.size() - 1; i > 0; i--) {
int index = random.nextInt(i + 1);
если (индекс <0) {
индекс = -индекс;
}
rawList.set(index, rawList.set(i, rawList.get(index)));
}
}
}
public static void main(final String args[]) {
Изменение объектаTemp;
List<Integer> numList = новый ArrayList<Integer>();
List<Integer> firstList = новый ArrayList<Integer>();
List<Integer> SecondList = новый ArrayList<Integer>();
List<Integer> ThirdList = новый ArrayList<Integer>();
List<Integer> fourList = новый ArrayList<Integer>();
for (int я = 1; я <= 100000; я++) {
numList.add (я);
firstList.add(я);
SecondList.add(я);
третийList.add(я);
четвёртыйList.add(я);
}
// первая перетасовка, используйте ChangeTemp
ПолучитьНачалоВремя();
интервал randInt = 0;
for (int i = 0, length = firstList.size(); i < length; i++) {
randInt = getRandom(i, firstList.size());
ChangeTemp = firstList.get(i);
firstList.set(i, firstList.get(randInt));
firstList.set(randInt, javaShuffle.temp);
}
getEndTime("Время первого перемешивания");
// вторая перетасовка, список обмена
ПолучитьНачалоВремя();
for (int i = 0, length = SecondList.size(); i < length; i++) {
randInt = getRandom(i, SecondList.size());
SecondList.set(i, SecondList.set(randInt, SecondList.get(i)));
}
getEndTime("Второе время тасования");
// третье перемешивание, изменение генерирует случайное целое число
ПолучитьНачалоВремя();
Object[] tempArray = ThirdList.toArray();
Случайный рандом = новый Random();
интервал j = 0;
for (int i = tempArray.length - 1; i > 0; i--) {
j = rand.nextInt(я + 1);
ThirdList.set(i, ThirdList.set(j, ThirdList.get(i)));
}
getEndTime("Третье время выполнения тасования");
// четвертое перемешивание, имитируем перетасовку Java
ПолучитьНачалоВремя();
Случайный случайный = новый случайный();
if (!(четвертый экземпляр RandomAccess)) {
Массив Object[] = fourList.toArray();
for (int i = array.length - 1; i > 0; i--) {
int index = random.nextInt(i + 1);
если (индекс < 0) {
индекс = -индекс;
}
Температура объекта = массив[i];
массив[i] = массив[индекс];
массив [индекс] = температура;
}
интервал я = 0;
ListIterator<Integer> it = (ListIterator<Integer>) fourList.listIterator();
в то время как (it.hasNext()) {
это.следующий();
it.set((Целое число) массив[i++]);
}
} еще {
Список <Целое число> rawList = (Список <Целое число>) четвёртый список;
for (int i = rawList.size() - 1; i > 0; i--) {
int index = random.nextInt(i + 1);
если (индекс <0) {
индекс = -индекс;
}
rawList.set(index, rawList.set(i, rawList.get(index)));
}
}
getEndTime("время четвертого тасования");
// перетасовка Java
ПолучитьНачалоВремя();
Коллекции.shuffle(numList);
getEndTime("Время выполнения перетасовки Java");
}
public static void swap(int a, int b) {
javaShuffle.temp = а;
а = б;
б = javaShuffle.temp;
}
public static int getRandom(final int low, Final int high) {
return (int) (Math.random() * (высокий – низкий) + низкий);
}
public static void getStartTime() {
javaShuffle.start = System.nanoTime();
}
public static void getEndTime(final String s) {
javaShuffle.end = System.nanoTime();
System.out.println(s + ": " + (javaShuffle.end - javaShuffle.start) + "ns");
}
}
如果数值较小,例如100000级别,则输出大概是:
время первого тасования: 85029499нс
время второго тасования: 80909474нс
время выполнения третьего тасования: 71543926нс
время выполнения четвертого тасования: 76520595нс
Время выполнения Java Shuffle: 61027643ns
время первого тасования: 82326239нс
время второго тасования: 78575611нс
время выполнения третьего тасования: 95009632нс
время выполнения четвертого тасования: 105946897нс
Время выполнения Java Shuffle: 90849302ns
время первого тасования: 84539840 нс
время второго тасования: 85965575нс
время выполнения третьего тасования: 101814998нс
время выполнения четвертого тасования: 113309672нс
Время выполнения Java Shuffle: 35089693 нс
время первого тасования: 87679863нс
время второго тасования: 79991814нс
время выполнения третьего тасования: 73720515нс
время выполнения четвертого тасования: 78353061нс
Время выполнения Java Shuffle: 64146465 нс
время первого тасования: 84314386нс
время второго тасования: 80074803нс
время выполнения третьего тасования: 74001283нс
время четвертого тасования: 79931321нс
Время выполнения Java Shuffle: 86427540 нс
время первого тасования: 84315523нс
время второго тасования: 81468386нс
время выполнения третьего тасования: 75052284нс
время выполнения четвертого тасования: 79461407нс
Время выполнения Java Shuffle: 66607729ns
如果是10000000级别,大概如下:
время первого тасования: 2115703288нс
время второго тасования: 3114045871нс
время выполнения третьего тасования: 4664426798нс
время четвертого тасования: 2962686695нс
Время выполнения Java в случайном порядке: 3246883026 нс. Время первого выполнения в случайном порядке: 2165398466 нс.
время второго тасования: 3129558913нс
время выполнения третьего тасования: 4147859664нс
время выполнения четвертого тасования: 2911849942нс
Время выполнения Java в случайном порядке: 4311703487нс. Время первого выполнения в случайном порядке: 2227462247нс.
время второго тасования: 3279548770нс
время выполнения третьего тасования: 4704344954нс
время выполнения четвертого тасования: 2942635980нс
Время выполнения Java в случайном порядке: 3933172427нс. Время первого выполнения в случайном порядке: 2200158789нс.
время второго тасования: 3172666791нс
время выполнения третьего тасования: 4715631517нс
время выполнения четвертого тасования: 2950817535нс
Время выполнения Java в случайном порядке: 3387417676 нс. Время первого выполнения в случайном порядке: 2201124449 нс.
время второго тасования: 3203823874нс
время выполнения третьего тасования: 4179926278нс
время четвертого тасования: 2913690411нс
Время выполнения Java в случайном порядке: 3571313813нс. Время первого выполнения в случайном порядке: 2163053190нс.
время второго тасования: 3073889926нс
время выполнения третьего тасования: 4493831518нс
время четвертого тасования: 2852713887нс
Время выполнения Java Shuffle: 3773602415ns
可以看出,第一种方法速度最快,而第四种最慢。java自带 shuffle速度也不理想。
在进行大数据处理的时候, 如果使用java库效率较低时,可以考虑使用其他方式。