乱序的意思想必没有不知道:就是将数组打乱。
听到乱序一般都会想到js的随机函数Math.random();

var values = [1, 2, 3, 4, 5];
values.sort(function() {
return Math.random() - 0.5;
});
console.log(values)
利用数组的sort方法,判断随机出来的0~1值与0.5的大小,实现排序。
看似一个很不错的方案,代码逻辑也没毛病,一般情况下也确实能够做到乱序。但是,这是一个伪排序,是的还有但是(我也是今天才知道的,不求甚解的毛病啊~),为什么呢?先看看这个乱序的结果吧:

var times = [0, 0, 0, 0, 0];
for (var i = 0; i < 100000; i++) {
let arr = [1, 2, 3, 4, 5];
arr.sort(() => Math.random() - 0.5);
times[arr[4] - 1]++;
};
console.log(times)

测试的原理是:将[1, 2, 3, 4, 5]乱序10万次,计算乱序后数组的最后一个元素是1,2,3,4,5的次数分别是多少。

运行几次得到的结果为:
 
 
 
由这几次运行得到的结果可以看出:2出现的最后的次数明显少于其他数字,不是随机吗?按理说概率应该是相差不多才对啊!
其实问题是在sort方法,各个浏览器对sort的实现方式不一样。
 
Chrome的sort
基于V8引擎,它的排序算进行了很多的优化,但是核心是小于等于10的数组用插入排序(稳定),大于10的采用了quickSort(不稳定)
 
FireFox的sort
基于SpiderMonkey引擎,采用了归并排序(稳定)
 
Safari的sort
基于Nitro(JavaScriptCore )引擎,如果没有自定义的排序规则传入,采用桶排序(不一定稳定, 桶排序的稳定性取决于桶内排序的稳定性, 因此其稳定性不确定。),传入自定义规则,采用归并排序(稳定)
 
Microsoft Edge/IE9+
基于Chakra引擎,采用快排(不稳定)
 
关于sort的不同具体说明见:https://zhuanlan.zhihu.com/p/33260052
 
以下用chrome测试乱序各种结果的概率:

var times = 100000;
var res = {};
for(var i = 0; i < times; i++){
var arr = [1, 2, 3];
arr.sort(() => Match.random() - 0.5);
var key = JSON.stringify(arr);
res[key] ? res[key]++ : res[key] = 1;
} // 为了方便展示,转换成百分比
for (var key in res) {
res[key] = res[key] / times * 100 + '%';
}
console.log(res);
所得结果如下:
 
几种结果出现的概率相差很大...所以说不是一个真正的乱序。
 
Fisher-Yates算法【也叫“洗牌算法”】:为什么叫 Fisher–Yates 呢? 因为这个算法是由 Ronald Fisher 和 Frank Yates 首次提出的。代码如下:
function shuffle(a) {
var j, x, i;
for (i = a.length; i; i--) {
j = Math.floor(Math.random() * i);
x = a[i-1];
a[i - 1] = a[j];
a[j] = x;
}
return a;
}
其原理就是:遍历数组元素,然后将当前元素与以后随机位置的元素进行交换,这样乱序更加彻底。
如果用ES6的写法还能精简成:
function shuffle(a) {
for(let i = a.length; i; i--) {
let j = Math.floor(Math.random() * i);
[a[i - 1], a[j]] = [a[j], a[i - 1]];
}
return a;
}

再用上面的demo测试一下:

var times = 100000;
var res = {}; for (var i = 0; i < times; i++) {
var arr = shuffle([1, 2, 3]); var key = JSON.stringify(arr);
res[key] ? res[key]++ : res[key] = 1;
} // 为了方便展示,转换成百分比
for (var key in res) {
res[key] = res[key] / times * 100 + '%'
} console.log(res)
得到结果如下:

各种结果的概率都基本相同了,所以真正实现了乱序的效果!

 
阅读Javascript专题之乱序:https://github.com/mqyqingfeng/Blog/issues/51 之笔记

最新文章

  1. 发一份shiro标准配置,特此记录
  2. JS 比较日期相隔都少天&amp;&amp; 比较两个日期大小&amp;&amp;指定日期往前后推指定天数
  3. WINDOWS下用脚本运行redis和mongodb
  4. win7(32/64)+apache2.4+php5.5+mysql5.6 环境搭建配置
  5. 如何使用 OneAPM 监控微软 Azure Cloud Service ?
  6. android 多语言版本开发
  7. C语言数据结构之栈:括号匹配
  8. android - DefaultHttpClient设置超时.
  9. poj 1364
  10. PHP的错误处理方式
  11. RPC通信框架——RCF介绍(替换COM)
  12. FindWindowEx使用方法
  13. 回答: 2017-03-19的关于css+div布局的疑问 2017-04-05
  14. Sphinx学习笔记(一)
  15. NumPy入门
  16. Redis的持久化之AOF方式
  17. 读取FTP 图片文件,并显示,非下载
  18. async-await用法
  19. ionic入门
  20. 【转】 多线程之linux线程调度策略

热门文章

  1. stm32串口烧写程序到开发板
  2. 剑指offer:滑动窗口的最大值(栈和队列)
  3. ubuntu18.04下安装无线网卡驱动心得
  4. WPF TabItem设置Visibility隐藏Control内容
  5. SQL Server中INSERT EXEC语句不能嵌套使用(转载)
  6. 微信分享网页时自定义缩略图和简介(.net版本)
  7. Winform中设置ZedGraph的曲线符号Symbol以及对应关系
  8. 算法笔记 第6章 C++标准模版库(STL)介绍 学习笔记
  9. 读oc52个有效方法的总结
  10. PowerShell美化