You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
这个算法由 Ronald Fisher 和 Frank Yates 于 1938 年提出,然后在 1964 年由 Richard Durstenfeld 改编为适用于电脑编程的版本。
举例:
constarray=[6,3,7,2,1];// 从后往前遍历,当前遍历元素为 v // v 为 1 的时候,从数组开始到 v(包括 v) 的范围内随机选择一个元素和 v 交换位置// v 为 2 的时候,从数组开始到 v(包括 v) 的范围内随机选择一个元素和 v 交换位置// 重复直到数组起始位置...
数组乱序:就是将数组内所有元素的顺序打乱,使每个元素随机出现在每个位置。
抽奖和洗牌等场景都会涉及到乱序。
微软调查案例
这是一个被到处提及的案例,大意是微软曾做过一个关于不同浏览器的使用情况的调查,需要在网页上按随机的顺序显示 5 款浏览器,这里用到的随机算法是:
这个算法乍一看感觉可以满足需求,但其实并不能实现完全的随机打乱数组。
也就是说数组中的每个元素,并不会随机出现在每个位置,而是在某些位置会更容易出现,并不是完全意义上的随机打乱。
在线验证
Will It Shuffle? 是一个通过可视化验证数组乱序算法可靠性的网站。
选择上述介绍的算法,查看可视化效果:
简单地说,颜色越多、差异越大、越不均匀,就说明算法的可靠性越差,也就是没有实现真正的随机乱序。
作为对比,选择另一个算法 —— Fisher–Yates 查看一下效果:
通过图片就能感受到两个算法之间的差距,就不用多说了。
原因分析
sort 的原理
sort
还可以接收一个函数(comprator
)作为参数。comprator
接收a
和b
两个参数,表示进行比较的两个元素。comprator
的返回值如果大于0
,a
就排在b
的后面;如果小于0
,a
就排在b
的前面;如果等于0
,a
和b
的位置保持不变。random 乱序的原理
Math.random()
的值在[0, 1)
之间,包含0
不包含1
。那么
Math.random() - 0.5
的值就在[-0.5, 0.5)
之间,包含-0.5
,不包含0.5
。所以
() => Math.random() - 0.5
的返回值大于0
和小于0
的概率各50%
。该乱序算法的原理就是通过随机返回大于或小于
0
的值来将a
和b
的顺序打乱,从而将整个数组的顺序打乱。random 乱序不可靠的原因
我们知道,
sort
方法在内部使用的是快速排序和插入排序相结合的方式,当数组长度小于10
的时候,采用插入排序进行排序。举例说明:
可靠的乱序
对 random 方法进行改造
上面说到
random
方法不可靠的原因在于比较函数每次的返回值是随机的,对于同样的输入,输出不稳定。基于这个思路,我们可以改造上述算法,让比较函数对于同样的输入,输出是不变的。
可视化效果:
Fisher–Yates shuffle
上面的方法虽然可以满足乱序的需求,但是性能并不好。
举例:
代码:
时间复杂度:O(n),
n
为数组长度。空间复杂度:O(1)。
参考资料
Will It Shuffle?
关于JavaScript的数组随机排序
「前端进阶」数组乱序
如何将一个 JavaScript 数组打乱顺序? - Lucas HC的回答 - 知乎
Doing the Microsoft Shuffle: Algorithm Fail in Browser Ballot
The text was updated successfully, but these errors were encountered: