javascript 洗牌算法
导语: Fisher–Yates Shuffle : 有时我们需要打乱一个数组,即为数组乱序,也称洗牌算法,以下记录一些常用的洗牌算法
一, 准备工作
~~ 1.5 ; 1.5 << 0 ; 1.5 >> 0 ; parseInt(1.5) 皆为对数字进行取整
二,洗牌算法
时间复杂度 o ( n^2 )
1 | function shuffle(a) { |
近似快速实现的算法
时间复杂度 o ( log(n) )
1 | function shuffle(a) { |
underscore中的实现, Fisher–Yates Shuffle 算法
时间复杂度 o(n)
1 | _.shuffle = function (obj) { |
Fisher–Yates Shuffle 算法
实现复杂度为: o ( n )
1 | function shuffle(a) { |
随机性的数学归纳法证明
对 n 个数进行随机
- 首先我们考虑 n = 2 的情况,根据算法,显然有 1/2 的概率两个数交换,有 1/2 的概率两个数不交换,因此对 n = 2 的情况,元素出现在每个位置的概率都是 1/2,满足随机性要求。
- 假设有 i 个数, i >= 2 时,算法随机性符合要求,即每个数出现在 i 个位置上每个位置的概率都是 1/i。
- 对于 i + 1 个数,按照我们的算法,在第一次循环时,每个数都有 1/(i+1) 的概率被交换到最末尾,所以每个元素出现在最末一位的概率都是 1/(i+1) 。而每个数也都有 i/(i+1) 的概率不被交换到最末尾,如果不被交换,从第二次循环开始还原成 i 个数随机,根据 2. 的假设,它们出现在 i 个位置的概率是 1/i。因此每个数出现在前 i 位任意一位的概率是 (i/(i+1)) * (1/i) = 1/(i+1),也是 1/(i+1)。
- 综合 1. 2. 3. 得出,对于任意 n >= 2,经过这个算法,每个元素出现在 n 个位置任意一个位置的概率都是 1/n。
小结
关于数组乱序,不要用 Math.random() 实现