通过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 相关文章推荐
jQuery 版元素拖拽原型代码
Apr 25 Javascript
jquery中子元素和后代元素的区别示例介绍
Apr 02 Javascript
node.js中的fs.writeFile方法使用说明
Dec 14 Javascript
javascript实现根据身份证号读取相关信息
Dec 17 Javascript
JavaScript实现图像模糊化的方法实例
Jan 15 Javascript
jquery 实时监听输入框值变化的完美方法(必看)
Jan 26 Javascript
Express + Session 实现登录验证功能
Sep 08 Javascript
使用 Vue 实现一个虚拟列表的方法
Aug 20 Javascript
使用vue-cli3+typescript的项目模板创建工程的教程
Feb 28 Javascript
JavaScript函数重载操作实例浅析
May 02 Javascript
基于elementUI竖向表格、和并列的案例
Oct 26 Javascript
Nuxt 项目性能优化调研分析
Nov 07 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中$_FILES的使用以及注意事项
2013/07/05 PHP
php基于GD库画五星红旗的方法
2015/02/24 PHP
php操作redis缓存方法分享
2015/06/03 PHP
PHP使用token防止表单重复提交的方法
2016/04/07 PHP
PHP + plupload.js实现多图上传并显示进度条加删除实例代码
2017/03/06 PHP
PHP实现关键字搜索后描红功能示例
2019/07/03 PHP
javascript Array数组对象的扩展函数代码
2010/05/22 Javascript
asp.net刷新本页面的六种方法总结
2014/01/07 Javascript
三种检测iPhone/iPad设备方向的方法
2014/04/23 Javascript
手写的一个兼容各种浏览器的javascript getStyle函数(获取元素的样式)
2014/06/06 Javascript
JavaScript中使用typeof运算符需要注意的几个坑
2014/11/08 Javascript
JS逆序遍历实现代码
2014/12/02 Javascript
javascript闭包的理解
2015/04/01 Javascript
jQuery实现下拉菜单(内容为时间)的实时更新及图表的随动更新的方法
2016/07/07 Javascript
封装的dialog插件 基于bootstrap模态对话框的简单扩展
2016/08/10 Javascript
jquery实现点击a链接,跳转之后,该a链接处显示背景色的方法
2018/01/18 jQuery
解决layui前端框架 form表单,table表等内置控件不显示的问题
2018/08/19 Javascript
使用validate.js实现表单数据提交前的验证方法
2018/09/04 Javascript
新年快乐! javascript实现超级炫酷的3D烟花特效
2019/01/30 Javascript
node省市区三级数据性能测评实例分析
2019/11/06 Javascript
微信小程序按顺序同步执行的两种方式
2019/12/20 Javascript
vue项目实现减少app.js和vender.js的体积操作
2020/11/12 Javascript
[00:44]TI7不朽珍藏III——军团指挥官不朽展示
2017/07/15 DOTA
深入理解Django中内置的用户认证
2017/10/06 Python
python2.7安装图文教程
2018/03/13 Python
Python嵌套列表转一维的方法(压平嵌套列表)
2018/07/03 Python
Django web框架使用url path name详解
2019/04/29 Python
Python如何基于selenium实现自动登录博客园
2019/12/16 Python
python主线程与子线程的结束顺序实例解析
2019/12/17 Python
Python Flask框架实现简单加法工具过程解析
2020/06/03 Python
365 Tickets英国:全球景点门票
2019/07/06 全球购物
数百万免费的图形资源:Freepik
2020/09/21 全球购物
简述数据库的设计过程
2015/06/22 面试题
党建目标管理责任书
2014/07/25 职场文书
java高级用法JNA强大的Memory和Pointer
2022/04/19 Java/Android
详解Mysql数据库平滑扩容解决高并发和大数据量问题
2022/05/25 MySQL