前言
先看一个段代码
function randArr (arr) {
return arr.sort(() => {
return (Math.random() - 0.5);
});
}复制代码
目的是为了实现给定数组的乱序。
利用数组的sort方法,判断随机出来的0~1的值与0.5的大小,实现伪排序。
为什么说是伪排序呢?代码的逻辑没毛病啊。
对,从这个层面来看,简单明了,完美的实现了需求,本着凡事往祖坟刨得精神。来看看这段代码的内部实现。
浏览器实现
ECMA Script
大致说的意思是,我不管你排序的算法稳不稳定,反正你能给用户自定义排序规则就行,不给你就爱咋折腾咋折腾~
这帮浏览器一听,好啊,老大发话了,那就八仙过海各显神通,各自都认为自己的实现是最牛逼的。
Chrome的sort
基于V8引擎,它的排序算进行了很多的优化,但是核心是小于等于10的数组用插入排序(稳定),大于10的采用了quickSort(不稳定),源码。
FireFox的sort
基于SpiderMonkey引擎,采用了归并排序(稳定), 源码
Safari的sort
基于Nitro(JavaScriptCore )引擎,如果没有自定义的排序规则传入,采用桶排序(不一定稳定, 桶排序的稳定性取决于桶内排序的稳定性, 因此其稳定性不确定。),传入自定义规则,采用归并排序(稳定),源码
Microsoft Edge/IE9+
基于Chakra引擎,采用快排(不稳定)源码
好了,那个说sort可以不是伪排序的同学,你看见我这40米的大刀没?
什么,你还嘴硬,我喜欢你的性格,看下面:
github上的大神对 var letters = ['A','B','C','D','E',‘F’,‘G’,'H','I','J'];
进行了10000次乱序处理,发现结论: 元素大概率停留在自己的初始位置。
具体地址: HOUCe/shuffle-array
看见没,矮要承认,挨打要立正。
洗牌算法(Fisher-Yates)
想要实现真正意义上的乱序,我们来研究一下:只要满足每个元素出现在各个位置的概率同等即可。
少年,听过如来神掌吗?
有个Fisher-Yates的洗牌算法,满足您的各种乱序需求,物美价廉,杀人越货居家旅行的必备精品~(其实有三个版本,有兴趣的自行搜索)
算法的大致描述
1.找到数组的屁股(最后一个元素);
2.在脑袋和屁股中间随机一个位置;
3.交换元素;
4.这时屁股是已经乱序后的元素,所以屁股前移;
5.如果屁股没打到脑袋上就继续1~4的步骤
function shuffle(arr) {
let length = arr.length,
r = length,
rand = 0;
while (r) {
rand = Math.floor(Math.random() * r--);
[arr[r], arr[rand]] = [arr[rand], arr[r]];
}
return arr;
}复制代码