通过js随机函数Math.random实现乱序


Posted in Javascript onMay 19, 2020

乱序的意思想必没有不知道:就是将数组打乱。听到乱序一般都会想到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的次数分别是多少。

运行几次得到的结果为:

通过js随机函数Math.random实现乱序通过js随机函数Math.random实现乱序通过js随机函数Math.random实现乱序

由这几次运行得到的结果可以看出:2出现的最后的次数明显少于其他数字,不是随机吗?按理说概率应该是相差不多才对啊!
其实问题是在sort方法,各个浏览器对sort的实现方式不一样。

Chrome的sort

基于V8引擎,它的排序算进行了很多的优化,但是核心是小于等于10的数组用插入排序(稳定),大于10的采用了quickSort(不稳定)

FireFox的sort

基于SpiderMonkey引擎,采用了归并排序(稳定)

Safari的sort

基于Nitro(JavaScriptCore )引擎,如果没有自定义的排序规则传入,采用桶排序(不一定稳定, 桶排序的稳定性取决于桶内排序的稳定性, 因此其稳定性不确定。),传入自定义规则,采用归并排序(稳定)

Microsoft Edge/IE9+

基于Chakra引擎,采用快排(不稳定)

以下用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);

结果如下

通过js随机函数Math.random实现乱序

几种结果出现的概率相差很大...所以说不是一个真正的乱序。

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)

得到结果如下:

通过js随机函数Math.random实现乱序

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javaScript checkbox 全选/反选及批量删除
Apr 28 Javascript
JavaScript 用Node.js写Shell脚本[译]
Sep 20 Javascript
通过location.replace禁止浏览器后退防止重复提交
Sep 04 Javascript
jquery 设置style:display的方法
Jan 29 Javascript
javascript中几个容易混淆的概念总结
Apr 14 Javascript
js时间戳和c#时间戳互转方法(推荐)
Feb 15 Javascript
详解vue表单——小白速看
Apr 08 Javascript
老生常谈JS中的继承及实现代码
Jul 06 Javascript
谈谈为什么你的 JavaScript 代码如此冗长
Jan 30 Javascript
使用layui定义一个模块并使用的例子
Sep 14 Javascript
微信小程序用户拒绝授权的处理方法详解
Sep 20 Javascript
Vue中用JSON实现刷新界面不影响倒计时
Oct 26 Javascript
javascript实现获取中文汉字拼音首字母
May 19 #Javascript
微信小程序实现菜单左右联动
May 19 #Javascript
JS array数组检测方式解析
May 19 #Javascript
基于JS实现table导出Excel并保留样式
May 19 #Javascript
vue利用全局导航守卫作登录后跳转到未登录前指定页面的实例代码
May 19 #Javascript
jQuery 函数实例分析【函数声明、函数表达式、匿名函数等】
May 19 #jQuery
JS加载解析Markdown文档过程详解
May 19 #Javascript
You might like
简单介绍下 PHP5 中引入的 MYSQLI的用途
2007/03/19 PHP
PHP实现获取文件后缀名的几种常用方法
2015/08/08 PHP
phpcms配置列表页以及获得文章发布时间
2017/07/04 PHP
php实现单笔转账到支付宝功能
2018/10/09 PHP
TP5框架简单登录功能实现方法示例
2019/10/31 PHP
PHP code 验证码生成类定义和简单使用示例
2020/05/27 PHP
JQuery SELECT单选模拟jQuery.select.js
2009/11/12 Javascript
一段批量给页面上的控件赋值js
2010/06/19 Javascript
jquery 关于event.target使用的几点说明介绍
2013/04/26 Javascript
通过javascript获取iframe里的值示例代码
2013/06/24 Javascript
简单的代码实现jquery定时器
2014/01/03 Javascript
JavaScript的null和undefined区别示例介绍
2014/09/15 Javascript
jQuery修改li下的样式以及li下的img的src的值的方法
2014/11/02 Javascript
js实现进度条的方法
2015/02/13 Javascript
js实现一个猜数字游戏
2017/03/31 Javascript
Angularjs上传图片实例详解
2017/08/06 Javascript
JS面向对象的程序设计相关知识小结
2018/05/26 Javascript
详解CommonJS和ES6模块循环加载处理的区别
2018/12/26 Javascript
vue自定义指令directive的使用方法
2019/04/07 Javascript
发布订阅模式在vue中的实际运用实例详解
2019/06/09 Javascript
js实现GIF图片的分解和合成
2019/10/24 Javascript
用Python从零实现贝叶斯分类器的机器学习的教程
2015/03/31 Python
python 查找字符串是否存在实例详解
2017/01/20 Python
详解Python之unittest单元测试代码
2018/01/24 Python
PyQt5每天必学之单行文本框
2018/04/19 Python
Python中zip()函数的简单用法举例
2019/09/02 Python
有关Tensorflow梯度下降常用的优化方法分享
2020/02/04 Python
Python制作数据预测集成工具(值得收藏)
2020/08/21 Python
基于PyInstaller各参数的含义说明
2021/03/04 Python
亚洲颇具影响力的男性在线购物零售商:His
2019/11/24 全球购物
家电业务员岗位职责
2014/03/10 职场文书
高三学习决心书
2014/03/11 职场文书
出差报告怎么写
2014/11/06 职场文书
详解JVM系列之内存模型
2021/06/10 Javascript
SpringBoot整合MongoDB的实现步骤
2021/06/23 MongoDB
MongoDB连接数据库并创建数据等使用方法
2021/11/27 MongoDB