我目前正在阅读《计算机科学:跨学科方法》一书,其中包含一个用于洗牌数组的代码片段(在本例中,数组包含一副纸牌)。代码如下:
int n = deck.length;
for (int i = 0; i < n; i++)
{
int r = i + (int) (Math.random() * (n-i));
String temp = deck[i];
deck[i] = deck[r];
deck[r] = temp;
}
我的问题是,为什么更简单的(int) (Math.random() * n)
不是首选?它比i + (int) (Math.random() * (n-i))
随机性低吗?
任何帮助表示赞赏!
它们给你不同的值。
(int) (Math.random() * n)
为您提供一个0 <= r < n
范围内的值(介于 0
[包括] 和n
[排除] 之间)。
i + (int) (Math.random() * (n-i))
为您提供一个i
<= r < n
范围内的值(介于 i
[包括] 和 n
[排除] 之间)。
因此,例如,如果i
是10
,您的"简化"版本可能会为您提供5
。代码中的版本不能。
这个想法是取一个尚未选择的随机值。如果您允许您的方案,那么某些元素可能永远不会被洗牌,因此某些元素留在原位的可能性太高。
Math.Random() 可以返回 0.0 到 1.0 之间的双精度值。
https://docs.oracle.com/javase/7/docs/api/java/lang/Math.html#random()
所以如果你只做(int) (Math.random() * n),那么r的值可以高于n-1,同时会导致ArrayIndexoutofbound异常。
http://docs.oracle.com/javase/7/docs/api/java/lang/ArrayIndexOutOfBoundsException.html