Беспристрастное перемешивание случайных массивов
Когда я хочу перетасовать массив чисел в массиве "perm" из [1...n], я написал на Java:
int[] perm = new int[n];
for (int i = 0; i < n; i++) {
perm[i] = i;
}
for (int i = 0; i < n; i++) {
int new_place = (int) (Math.random()*n); // Exchange element with any random element.
int temp = perm[new_place];
perm[new_place] = perm[i];
perm[i] = temp;
}
Но в книге рандомизирующий код написан как (только изменения в цикле for):
for (int i = 0; i < n; i++) {
int new_place = i + (int) (Math.random() * (n-i)); // Exchange element with a random element to its right.
int temp = perm[new_place];
perm[new_place] = perm[i];
perm[i] = temp;
}
и они говорят, что с помощью кода, который они пишут, они гарантируют, что тасование будет случайным, равномерно выбирая из карт, которые еще не выбраны. (В отличие от моего подхода, когда я выбираю из всех карт).(Я считаю, что они написали модифицированную версию алгоритма Фишера-Йейтса).
Я просто хочу знать, является ли мой код (приведенный выше) также беспристрастным для генерации случайных чисел или нет? Если да, то почему? Если нет, то почему?
(Первые 2 комментария относятся к вопросу, который я задал, правильно ли то, что я делаю, для генерации случайных чисел, но я хотел спросить, беспристрастно ли это. Но тогда я не знал этого термина, извините. Относительно текущего вопроса , 4-й комментарий имеет очень хорошую ссылку для понимания).
1 ответ
Ваш код, похоже, имеет предвзятость в распределении сгенерированного массива. Результаты 6000 статистики для
n = 3
следующие.
static int[] shuffle(int n) {
int[] perm = IntStream.range(0, n).toArray();
for (int i = 0; i < n; i++) {
int new_place = (int) (Math.random()*n);
int temp = perm[new_place];
perm[new_place] = perm[i];
perm[i] = temp;
}
return perm;
}
static final Comparator<int[]> INT_ARRAY_COMPARATOR = (a, b) -> Arrays.compare(a, b);
public static void main(String[] args) {
Map<int[], Integer> counts = new TreeMap<>(INT_ARRAY_COMPARATOR);
int n = 3;
for (int i = 0; i < 6000; ++i)
counts.compute(shuffle(n), (k, v) -> v == null ? 1 : v + 1);
counts.entrySet()
.forEach(e -> System.out.println(Arrays.toString(e.getKey()) + "=" + e.getValue()));
}
выход:
[0, 1, 2]=865
[0, 2, 1]=1113
[1, 0, 2]=1161
[1, 2, 0]=1093
[2, 0, 1]=873
[2, 1, 0]=895
[0, 1, 2]
и
[2, 1, 0]
кажутся нечастыми.
При выполнении с кодом книги это делается следующим образом.
static int[] shuffle(int n) {
int[] perm = IntStream.range(0, n).toArray();
for (int i = 0; i < n; i++) {
int new_place = i + (int) (Math.random() * (n-i));
int temp = perm[new_place];
perm[new_place] = perm[i];
perm[i] = temp;
}
return perm;
}
выход:
[0, 1, 2]=987
[0, 2, 1]=978
[1, 0, 2]=1014
[1, 2, 0]=994
[2, 0, 1]=1041
[2, 1, 0]=986
Я не могу объяснить, почему это так, но вы должны попробовать.