通过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语言结构小记(一)
Sep 10 Javascript
在firefox和Chrome下关闭浏览器窗口无效的解决方法
Jan 16 Javascript
利用javascript实现全部删或清空所选的操作
May 27 Javascript
JavaScript通过prototype给对象定义属性用法实例
Mar 23 Javascript
js结合正则实现国内手机号段校验
Jun 19 Javascript
纯jquery实现模仿淘宝购物车结算
Aug 20 Javascript
详解JavaScript基本类型和引用类型
Dec 09 Javascript
jQuery基于扩展简单实现倒计时功能的方法
May 14 Javascript
jQuery ajaxSubmit 实现ajax提交表单局部刷新
Jul 04 Javascript
微信小程序实现人脸检测功能
May 25 Javascript
vue使用过滤器格式化日期
Jan 20 Vue.js
一道JS算法面试题——冒泡、选择排序
Apr 21 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
阿拉伯的咖啡与水烟
2021/03/03 咖啡文化
PHP中的array数组类型分析说明
2010/07/27 PHP
测试php连接mysql是否成功的代码分享
2014/01/24 PHP
ThinkPHP分组下自定义标签库实例
2014/11/01 PHP
CI框架装载器Loader.php源码分析
2014/11/04 PHP
php自定义时间转换函数示例
2016/12/07 PHP
php读取XML的常见方法实例总结
2017/04/25 PHP
[原创]php token使用与验证示例【测试可用】
2017/08/30 PHP
用JavaScript 处理 URL 的两个函数代码
2007/08/13 Javascript
到处都是jQuery选择器的年代 不了解它们的性能,行吗
2012/06/18 Javascript
jquery对dom的操作常用方法整理
2013/06/25 Javascript
js replace 与replaceall实例用法详解
2013/08/03 Javascript
JavaScript数组去重的五种方法
2015/11/05 Javascript
jQuery+ajax简单实现文件上传的方法
2016/06/03 Javascript
BootStrap学习笔记之nav导航栏和面包屑导航
2017/01/03 Javascript
Node.js 异步异常的处理与domain模块解析
2017/05/10 Javascript
Vue动态加载图片在跨域时无法显示的问题及解决方法
2020/03/10 Javascript
vue中是怎样监听数组变化的
2020/10/24 Javascript
python实现每次处理一个字符的三种方法
2014/10/09 Python
Python实现Tab自动补全和历史命令管理的方法
2015/03/12 Python
Python操作MySQL数据库的三种方法总结
2018/01/30 Python
python3+selenium实现qq邮箱登陆并发送邮件功能
2019/01/23 Python
python列表每个元素同增同减和列表元素去空格的实例
2019/07/20 Python
Python3.0 实现决策树算法的流程
2019/08/08 Python
python urllib爬虫模块使用解析
2019/09/05 Python
Python使用socket_TCP实现小文件下载功能
2020/10/09 Python
OpenCV读取与写入图片的实现
2020/10/13 Python
LivingSocial英国:英国本地优惠
2019/02/22 全球购物
Diptyque英国官方网站:源自法国的知名香氛品牌
2019/08/28 全球购物
操行评语大全
2014/04/30 职场文书
个人工作主要事迹
2014/05/08 职场文书
2014年秋季开学典礼主持词
2014/08/02 职场文书
关于工作经历的证明书
2014/10/11 职场文书
优秀班主任申报材料
2014/12/16 职场文书
同事离别感言
2015/08/04 职场文书
python中的3种定义类方法
2021/11/27 Python