引言
前段时间面试碰到一道题,题目主要就是随机打乱一个数组的顺序。乍一听我觉得挺简单的,但是到写代码的时候却有种“无从下手”的感觉,原因在于自己其实之前并没有使用过(也没有仔细思考过)“随机性”。
产生指定范围的随机数
Math.random()
返回一个随机数,均匀分布在[0,1)
范围。用这个方法我们可以在任意范围产生随机数。
比如
-
Math.random()*10
:均匀分布在[0,10)
范围的有理数。 -
Math.floor(Math.random()*10)
:均匀分布在[0,9]
范围的整数(得到0~9这10个整数的概率相同)。 -
Math.floor(Math.random()*10)+55
:均匀分布在[55,64]
范围的整数(得到这10个整数的概率相同)。
更一般化的,产生指定范围的随机有理数方法:
// 产生一个[min,max)范围的随机有理数
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}
产生指定范围的随机整数的方法:
// 产生一个[min,max]范围的随机整数,注意这个范围包含max
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
上面这个方法中的+ 1
是一个很容易遗漏的地方,考虑一下为什么Math.floor(Math.random()*10)
最大只能产生9。
用随机数打乱数组
一个简洁的办法是,利用sort:
function shuffle(array) {
array.sort(function() {
return 0.5 - Math.random();
});
}
但是这种方法并不能做到真正的“均匀打乱”,可以看看参考资料3中的知乎讨论。
这位答主结合生动的图片解释了更好的均匀打乱算法:Fisher–Yates shuffle。
function shuffle(array) {
var m = array.length,
t, i;
while (m) {
i = Math.floor(Math.random() * m--);
t = array[m];
array[m] = array[i];
array[i] = t;
}
return array;
}
这里就不盗人家的图了,读者可以点击链接查看。
这个简洁的算法不难理解,主要的步骤是i = Math.floor(Math.random() * m--)
,这个语句先获取一个[0,m-1]
范围的随机下标赋值给i
,然后m=m-1
。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。