通过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 相关文章推荐
限制文本字节数js代码
Mar 06 Javascript
基于jQuery的左右滚动实现代码
Dec 03 Javascript
TextArea不支持maxlength的解决办法(jquery)
Sep 13 Javascript
20个实用的JavaScript技巧分享
Nov 28 Javascript
Javascript基础_嵌入图像的简单实现
Jun 14 Javascript
详解Angular4中路由Router类的跳转navigate
Jun 09 Javascript
jQuery Ajax使用FormData上传文件和其他数据后端web.py获取
Jun 11 jQuery
vue绑定设置属性的多种方式(5)
Aug 16 Javascript
Vue网页html转换PDF(最低兼容ie10)的思路详解
Aug 24 Javascript
Vue2.0用 watch 观察 prop 变化(不触发)
Sep 08 Javascript
一次让你了解全部JavaScript的作用域
Jun 24 Javascript
微信小程序实现图片压缩
Dec 03 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
社区(php&amp;&amp;mysql)四
2006/10/09 PHP
FleaPHP的安全设置方法
2008/09/15 PHP
一段非常简单的让图片自动切换js代码
2006/11/10 Javascript
JS应用之禁止抓屏、复制、打印
2008/02/21 Javascript
根据经纬度计算地球上两点之间的距离js实现代码
2013/03/05 Javascript
JS图片根据鼠标滚动延时加载的实例代码
2013/07/13 Javascript
js中通过split函数分割字符串成数组小例子
2013/09/21 Javascript
js如何获取兄弟、父类等节点
2014/01/06 Javascript
JavaScript资源预加载组件和滑屏组件的使用推荐
2016/03/10 Javascript
JS中正则表达式全局匹配模式 /g用法详解
2017/04/01 Javascript
Javascript实现的StopWatch功能示例
2017/06/13 Javascript
深入理解vue $refs的基本用法
2017/07/13 Javascript
解决JQuery全选/反选第二次失效的问题
2017/10/11 jQuery
使用 Javascript 实现浏览器推送提醒功能的示例
2017/11/03 Javascript
JS和JQuery实现雪花飘落效果
2017/11/30 jQuery
浅谈Vue.js中ref ($refs)用法举例总结
2017/12/19 Javascript
Vue-cli配置打包文件本地使用的教程图解
2018/08/02 Javascript
jQuery实现的淡入淡出图片轮播效果示例
2018/08/29 jQuery
js设计模式之单例模式原理与用法详解
2019/08/15 Javascript
[01:01:51]EG vs VG Supermajor小组赛B组 BO3 第二场 6.2
2018/06/03 DOTA
linux系统使用python监测系统负载脚本分享
2014/01/15 Python
python字符串的常用操作方法小结
2016/05/21 Python
Python中文件I/O高效操作处理的技巧分享
2017/02/04 Python
python 去除txt文本中的空格、数字、特定字母等方法
2018/07/24 Python
使用python将请求的requests headers参数格式化方法
2019/01/02 Python
python3通过selenium爬虫获取到dj商品的实例代码
2019/04/25 Python
Python math库 ln(x)运算的实现及原理
2019/07/17 Python
Python3+Requests+Excel完整接口自动化测试框架的实现
2019/10/11 Python
详解python statistics模块及函数用法
2019/10/27 Python
物流管理专业大学生自荐信
2013/10/04 职场文书
多媒体专业自我鉴定
2014/02/28 职场文书
学生安全责任书模板
2014/07/25 职场文书
庆国庆国旗下讲话稿2014
2014/09/21 职场文书
win10安装配置nginx的过程
2021/03/31 Servers
Mysql效率优化定位较低sql的两种方式
2021/05/26 MySQL
如何用六步教会你使用python爬虫爬取数据
2022/04/06 Python