【发布时间】:2021-08-06 22:15:41
【问题描述】:
当我想从 [1...n] 中对数组“perm”中的数字数组进行洗牌时,我用 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;
}
他们说,通过他们编写的代码,他们通过从尚未选择的卡片中统一选择来确保洗牌是随机的。 (与我的方法相反,我从所有卡片中选择)。 (我相信这是他们写的Fisher-Yates算法的修改版)。
我只想知道我的代码(上面的代码)是否也对随机数生成没有偏见?如果是,为什么?如果不是,为什么?
(前 2 个 cmets 是针对我问我所做的是否对随机数生成正确的问题,但我想问它是否无偏。但我当时不知道这个术语,对不起。对于这个当前的问题,第4条评论有一个很好的理解链接)。
【问题讨论】:
-
只要您的随机数生成生成从 0 到 n 的值,最终数组的所有排列都是同样可能的。你的代码是正确的。
-
小心将
Math.random()转换为int,因为如果没有括号,它将返回0。您可以声明一个随机对象Random rand = new Random()并说int r = rand.nextInt(n) -
@NeonFire 对不起,我忘了添加随机数组应该是无偏的。你知道我应该编辑这个问题还是创建一个新问题?谢谢。
-
不,你的算法(一个天真的洗牌)不是没有偏见的。这是一个很好的explanation 为什么不呢。
-
NeonFIre 和 Gene 都不正确,RaffleBuffle 的链接对此进行了解释,saka1029 的答案在示例输出中进行了演示。正如 Jeff 解释的那样,当您将元素与 any 元素交换时,当前元素“左侧”的元素之前已经至少交换过一次,从而导致比实际可能的排列更多的组合在 Coding Horror 博客文章中。
标签: java arrays shuffle fisher-yates-shuffle