通过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,超强推荐expand.js
Dec 23 Javascript
node.js 一个简单的页面输出实现代码
Mar 07 Javascript
将字符串转换成gb2312或者utf-8编码的参数(js版)
Apr 10 Javascript
JQuery调用WebServices的方法和4个实例
May 06 Javascript
JavaScript实现向OL列表内动态添加LI元素的方法
Mar 21 Javascript
AngularJS实现一次监听多个值发生的变化
Aug 31 Javascript
jQuery通过ajax方法获取json数据不执行success的原因及解决方法
Oct 15 Javascript
从零开始学习Node.js系列教程之设置HTTP头的方法示例
Apr 13 Javascript
使用3D引擎threeJS实现星空粒子移动效果
Sep 13 Javascript
Vue组件创建和传值的方法
Aug 17 Javascript
使用JS实现动态时钟
Mar 12 Javascript
vue实现前端列表多条件筛选
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
php实现邮件发送并带有附件
2014/01/24 PHP
PHP生成自定义长度随机字符串的函数分享
2014/05/04 PHP
解决php用mysql方式连接数据库出现Deprecated报错问题
2019/12/25 PHP
javascript之水平横向滚动歌词同步的应用
2007/05/07 Javascript
11个用于提高排版水平的基于jquery的文字效果插件
2012/09/14 Javascript
fancybox modal的完美解决(右上的X)
2012/10/30 Javascript
js中关于一个分号的崩溃示例
2013/11/11 Javascript
jquery form 加载数据示例
2014/04/21 Javascript
使用jQuery和Bootstrap实现多层、自适应模态窗口
2014/12/22 Javascript
jQuery+Pdo编写login登陆界面
2016/08/01 Javascript
js倒计时小实例(多次定时)
2016/12/08 Javascript
Bootstrap3 内联单选和多选框
2016/12/29 Javascript
12条写出高质量JS代码的方法
2018/01/07 Javascript
Vue组件库发布到npm详解
2018/02/17 Javascript
JavaScript事件对象event用法分析
2018/07/27 Javascript
bootstrap模态框关闭后清除模态框的数据方法
2018/08/10 Javascript
详解react内联样式使用webpack将px转rem
2018/09/13 Javascript
微信小程序提取公用函数到util.js及使用方法示例
2019/01/10 Javascript
vscode配置vue下的es6规范自动格式化详解
2019/03/20 Javascript
用Node写一条配置环境的指令
2019/11/14 Javascript
利用Python批量压缩png方法实例(支持过滤个别文件与文件夹)
2017/07/30 Python
python xlwt如何设置单元格的自定义背景颜色
2019/09/03 Python
Python原始套接字编程实例解析
2020/01/29 Python
新西兰航空中国官网:Air New Zealand China
2018/07/24 全球购物
Skyscanner香港:机票比价, 平机票和廉价航空机票预订
2020/02/07 全球购物
意大利时尚奢侈品店:D’Aniello Boutique
2021/01/19 全球购物
统计每一学生的平均成绩
2014/06/06 面试题
教师简历自我评价
2014/02/03 职场文书
《独坐敬亭山》教学反思
2014/04/08 职场文书
终止合同协议书
2014/04/17 职场文书
交通事故赔偿协议书
2014/10/16 职场文书
小英雄雨来观后感
2015/06/09 职场文书
蜗居观后感
2015/06/11 职场文书
2016年先进教师个人事迹材料
2016/02/26 职场文书
人民币符号
2022/02/17 杂记
Go gRPC进阶教程gRPC转换HTTP
2022/06/16 Golang