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

运行几次得到的结果为:
 
 
 
由这几次运行得到的结果可以看出:2出现的最后的次数明显少于其他数字,不是随机吗?按理说概率应该是相差不多才对啊!
其实问题是在sort方法,各个浏览器对sort的实现方式不一样。
 
Chrome的sort
基于V8引擎,它的排序算进行了很多的优化,但是核心是小于等于10的数组用插入排序(稳定),大于10的采用了quickSort(不稳定)
 
FireFox的sort
基于SpiderMonkey引擎,采用了归并排序(稳定)
 
Safari的sort
基于Nitro(JavaScriptCore )引擎,如果没有自定义的排序规则传入,采用桶排序(不一定稳定, 桶排序的稳定性取决于桶内排序的稳定性, 因此其稳定性不确定。),传入自定义规则,采用归并排序(稳定)
 
Microsoft Edge/IE9+
基于Chakra引擎,采用快排(不稳定)
 
关于sort的不同具体说明见:https://zhuanlan.zhihu.com/p/33260052
 
以下用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);
所得结果如下:
 
几种结果出现的概率相差很大...所以说不是一个真正的乱序。
 
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)
得到结果如下:

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

 
阅读Javascript专题之乱序:https://github.com/mqyqingfeng/Blog/issues/51 之笔记

javascript专题系列--js乱序的更多相关文章

  1. javascript洗牌算法 乱序算法 面试题

    1.2种方案代码 <!DOCTYPE html> <html lang="zh"> <head> <meta charset=" ...

  2. javascript专题系列--尾调用和尾递归

    最近在看<冴羽的博客>,讲真,确实受益匪浅,已经看了javascript 深入系列和专题系列的大部分文章,可是现在才想起来做笔记.所以虽然很多以前面试被问得一脸懵逼的问题都被“一语惊醒梦中 ...

  3. JavaScript tips —— 谈谈数组乱序

    前言 先看一个段代码 function randArr (arr) { return arr.sort(() => { return (Math.random() - 0.5); }); } 目 ...

  4. JavaScript 专题系列第六篇,讲解深浅拷贝的技巧和以及实现深浅拷贝的思路

    拷贝也是面试经典呐! 数组的浅拷贝 如果是数组,我们可以利用数组的一些方法比如:slice.concat 返回一个新数组的特性来实现拷贝. 比如:   var arr = ['old', 1, tru ...

  5. 字串乱序 PHP&JS

    <?php /** * 字串乱序 PHP&JS * * php 中把字串乱序后输出给客户机的 JAVASCRIPT , JAVASCRIPT 中恢复 * 在指定长度提取一个字符,并把这一 ...

  6. 字串乱序 PHP&JS

    <?php /** * 字串乱序 PHP&JS * * php 中把字串乱序后输出给客户机的 JAVASCRIPT , JAVASCRIPT 中恢复 * 在指定长度提取一个字符,并把这一 ...

  7. 总结下js排序算法和乱序算法

    其实本人最怕的就是算法,大学算法课就感觉老师在讲天书,而且对于前端来说,算法在实际的应用中实在是很有限.毕竟算法要依靠大量的数据为基础才能发挥出算法的效率,就浏览器那性能,......是吧,退一万步说 ...

  8. HTML5之2D物理引擎 Box2D for javascript Games 系列 翻外篇--如何结合createJS应用box2d.js

    太久没有更新了,新年回来工作,突然有收到网友的邮件提问,居然还有人在关注,惭愧,找了下电脑上还有一点儿存着,顺便先发这一个番外篇吧,好歹可以看到真实的效果,等我考完英语,一定会更新下一章," ...

  9. js之数组乱序

    这是最近面试遇到的,不过忘记了,之前也有印象刷到过这道题,就再次记录一下加深印象吧,听到最多的答案是利用sort方法,不过也有说这种方法不好,利用了快排和插入排序,那就整理下吧 <!DOCTYP ...

随机推荐

  1. MySQL实战45讲学习笔记:第四十三讲

    一.本节概述 我经常被问到这样一个问题:分区表有什么问题,为什么公司规范不让使用分区表呢?今天,我们就来聊聊分区表的使用行为,然后再一起回答这个问题. 二.分区表是什么? 为了说明分区表的组织形式,我 ...

  2. Python连载33-共享变量加锁、释放

    一.共享变量 共享变量:当多个线程访问同一个变量的时候.会产生共享变量的问题. 例子: import threading sum = 0 loopSum = 1000000 def myAdd(): ...

  3. 我的周记13——”离开,是为了更好的回来"

    一点分享 生存是一种即时策略游戏,所有的人都是这场游戏的玩家.财务自由了,就是游戏赢家. 具体来说,又分成两种游戏:财富游戏和地位游戏.财富游戏的玩家追求更多的财富,地位游戏的玩家追求更高的地位. 古 ...

  4. 如何在yii1.0.7中设置数据库连接超时?

    继承CDbConnection, 覆盖 init()方法 在 parent::init() 之前设置 $this->setAttribute(PDO::ATTR_TIMEOUT, $this-& ...

  5. kali渗透综合靶机(八)--Billu_b0x靶机

    kali渗透综合靶机(八)--Billu_b0x靶机 靶机下载地址:https://download.vulnhub.com/billu/Billu_b0x.zip 一.主机发现 1.netdisco ...

  6. Docker入门学习及其安装

    1.Docker是一个开源的应用容器引擎,基于Go语言并遵从Apache2.0协议开源.Docker可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布到任何流行的Linux机器 ...

  7. C#网页 截图

    using System.IO; using System.Drawing; using System.Drawing.Imaging; using System.Threading; using S ...

  8. UWP使用TreeView

    这个帖子本来是不想写的,但是感觉网上类似的也没有,对于小白可能有点用,于是想着还是写一下吧. 写之前想说下,UWP其实并没有死掉,对于win10来说,以后的新设备肯定是支持UWP的,而且微软一直在完善 ...

  9. DevExpress的图形按钮菜单栏控件WindowsUIButtonPanel的布局、使用和设置按钮的点击事件

    场景 Winform控件-DevExpress18下载安装注册以及在VS中使用: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1 ...

  10. Winform中实现设置ZedGraph的GraphPane的大小匹配ZedGraphControl

    场景 Winforn中设置ZedGraph曲线图的属性.坐标轴属性.刻度属性: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/10 ...