前言

对数组进行排序对我们来说很容易就能够实现,但是你有考虑过如何对一个有序的数组实现乱序,即随机排序吗?

数组乱序在实际开发过程中是可能碰到的,下面我们一起看看如何实现数组乱序。

欢迎关注我的微信公众号:前端极客技术(FrontGeek)

sort + Math.random

我们一开始可能会想到利用数组的sort方法,判断随机出来的0-1的值与0.5的大小,实现排序。该方法实现如下:

var arr = [1, 2, 3, 4, 5, 6];arr.sort(function(){return Math.random() - 0.5;
});console.log(arr)

上面的实现方法看起来很完美地实现了乱序的需求,但实际的效果如何我们还是要进行测试。

对sort + Math.random方法进行测试

在Chrome浏览器上将[1, 2, 3, 4, 5]数组进行乱序10万次,计算乱序后每个值出现在各个位置的概率。测试代码如下:

let statistics = new Array(5).fill(0).map(() => new Array(5).fill(0));
for (let i = 0; i < 100000; i++) {let arr = [1, 2, 3, 4, 5];arr.sort(() => Math.random() - 0.5);arr.forEach((value, index) => {statistics[index][value - 1]++;})
}
console.table(statistics.map(item => item.map(value => (value / 100000 * 100).toFixed(2) + '%')));

在Chrome浏览器上执行得到如下结果:

从上图我们可以看出:元素出现在每个位置上的概率并没有趋向于相等,反而元素停留在原位置上的概率更大,所以Array.sort()方法进行乱序是存在问题的。要知道问题具体出现在哪,我们需要了解sort方法实现原理。

Array.sort()方法的实现

ECMAScript对 Array.prototype.sort 的定义只规定了效果,没有要求用什么样的排序方式实现sort()方法,也没有要求是否要采用稳定排序算法,所以不同的浏览器实现的方式都不太一样。

Chrome的sort

基于V8引擎,它的排序算法进行了很多的优化,但核心是小于等于10的数组用插入排序,大于10的采用快速排序。

FireFox的sort

基于SpiderMonkey引擎,采用归并排序。

Safari的sort

基于Nitro(JavaScriptCore) 引擎,如果没有自定义的排序规则传入,采用桶排序;传入自定义规则,采用归并排序。

Microsoft Edge/IE9+ 的sort

基于Chakra引擎,采用快速排序。

分析

其实不管用什么排序方法,大多数排序算法的时间复杂度介于O(n)到O(n2)之间,元素之间的比较次数通常情况下要远小于n(n-1)/2,也就意味着有一些元素之间根本就没机会相比较(也就没有了随机交换的可能),这些 sort 随机排序的算法自然也不能真正随机。

怎么理解上边这句话呢?其实我们想使用array.sort进行乱序,理想的方案或者说纯乱序的方案是数组中每两个元素都要进行比较,这个比较有50%的交换位置概率。这样一来,总共比较次数一定为n(n-1)。而在sort排序算法中,大多数情况都不会满足这样的条件。因而当然不是完全随机的结果了。

这里我们以Chrome使用的插入排序算法为例:在插入排序的算法中,当待排序元素跟有序元素进行比较时,一旦确定了位置,就不会再跟位置前面的有序元素进行比较,所以就出现了前面说的“没有了随机交换的可能”的情况,导致乱序不彻底。

要实现真正意义上的乱序,这就要提到经典的 洗牌算法Fisher–Yates_shuffle。

洗牌算法Fisher–Yates_shuffle

Fisher–Yates_shuffle的原理如下:

1、写下从 1 到 N 的数字
2、取一个从 1 到剩下的数字(包括这个数字)的随机数 k
3、从低位开始,得到第 k 个数字(这个数字还没有被取出),把它写在独立的一个列表的最后一位
4、重复第 2 步,直到所有的数字都被取出
5、第 3 步写出的这个序列,现在就是原始数字的随机排列

简单的说:就是随机抽一个放到最后。把剩余的数继续抽,继续放到次后。。。。依次执行

实现代码如下:

function shuffle(array) {var j, x, i;for (i = array.length; i; i--) {j = Math.floor(Math.random() * i);x = array[i - 1];array[i - 1] = array[j];array[j] = x;}return array;
}

我们对上面实现的方法进行10万次乱序:

var statistics = new Array(5).fill(0).map(() => new Array(5).fill(0));
for (let i = 0; i < 100000; i++) {let arr = [1, 2, 3, 4, 5];arr = shuffle(arr);arr.forEach((value, index) => {statistics[index][value - 1]++;})
}
console.table(statistics.map(item => item.map(value => (value / 100000 * 100).toFixed(2) + '%')));

统计结果如下:

从上图可以看出,数组中任意一个元素出现在任何一个位置的概率都是相等的,这样我们就真正实现了乱序的效果。

欢迎关注我的微信公众号:前端极客技术(FrontGeek)

JavaScript-数组乱序相关推荐

  1. .NET如何写正确的“抽奖”——数组乱序算法

    .NET如何写正确的"抽奖"--数组乱序算法 数组乱序算法常用于抽奖等生成临时数据操作.就拿年会抽奖来说,如果你的算法有任何瑕疵,造成了任何不公平,在年会现场 code revie ...

  2. (1)数组乱序(3)数组中获取随机数

    (1)数组乱序 created() {// (1)数组乱序let res1 = this.getarrScrambling([1, 2, 3,4,5]);console.log(res1);let a ...

  3. JavaScript习题(数组去重、有序数组乱序排列)

    数组去重 Array.prototype.unique = function(){var temp = {},arr = [],len = this.length;for(var i = 0 ; i ...

  4. c++中怎么数组内有用元素的个数_前端面试(算法篇) - 数组乱序

    一.面试题 问:有一个长度为 100 的数组,如何从中随机挑选 50 个元素,组成一个新的数组? 答:这个...那个...emmmmmm 问:那先不挑 50 个,就挑一个数,知道怎么做吗? 答:这个我 ...

  5. java 乱序算法_前端面试(算法篇) - 数组乱序

    一.面试题 问:有一个长度为 100 的数组,如何从中随机挑选 50 个元素,组成一个新的数组? 答:这个...那个...emmmmmm 问:那先不挑 50 个,就挑一个数,知道怎么做吗? 答:这个我 ...

  6. JavaScript数组的定义及常用方法

    目录 前言 一.数组是什么? 二.数组的定义方式 1.字面量方法 2.构造函数创建 三.数组常用方法 1.push:在数组最后一位添加方法,可添加多个 2.pop:把数组的最后一位剪切(传参无效) 3 ...

  7. iOS之数组的排序(升序、降序及乱序)

    1 #pragma mark -- 数组排序方法(升序) 2 3 - (void)arraySortASC{ 4 5 //数组排序 6 7 //定义一个数字数组 8 9 NSArray *array ...

  8. 笔试算法题(28):删除乱序链表中的重复项 找出已经排好序的两个数组中的相同项...

    出题:给定一个乱序链表,节点值为ASCII字符,但是其中有重复项,要求去除重复项并保证不改变剩余项的原有顺序: 分析:创建一个256(2^8)大小的bool数组,初始化为false,顺序读取链表,将字 ...

  9. php 数组 打乱顺序,PHP数组随机乱序和反序的实例详解

    PHP数组随机乱序和反序 在前两篇文章<如何对PHP数组进行排序>和<PHP数组的倒序>中介绍了两组函数,一组升序,一组倒序(降序),今天我们这篇文章跟大家介绍数组的随机乱序和 ...

最新文章

  1. 字符编码笔记:ASCII,Unicode和UTF-8
  2. 《大数据分析原理与实践》——导读
  3. 【单页应用巨坑之History】细数History带给单页应用的噩梦
  4. 标签传播算法(Label Propagation)及Python实现
  5. 前端学习(1945)vue之电商管理系统电商系统之调用api获取数据
  6. requests由于系统缓冲区空间不足_系统C盘满了空间不足的扩容?
  7. python实现输入三角形边长自动作图求面积案例
  8. php-cli和php-fpm FastCgi与PHP-fpm之间的关系
  9. PHP三维数组变一维
  10. css-modules,CSS Modules 方案
  11. Julia: 引用与copy: 关于数组、自定义类型与初始化
  12. 6,EWF写保护功能介绍与使用
  13. 有关照度和亮度的单位
  14. Kubernetes——KubeSphere部署worldpress应用
  15. 【vs】 试图加载格式不正确的程序
  16. unity-动画 Animation read-only 问题
  17. 程序员应该每天写代码
  18. Vue实例生命周期函数(钩子函数)详解
  19. helm安装cert-manager自动化Https(1.8)
  20. python数据分析师工作内容_小白入行数据分析师3年-工作内容复盘分享含代码(一)-Python篇介绍...

热门文章

  1. codevs 搜索题汇总(黄金级)
  2. 全球“黑客大赛”冠军霸气讲述:我是如何让50个文件一起骗过AI安防系统的?...
  3. linux 命令 (不断更新)
  4. 阿里妈妈api接口测试
  5. 【软购商城】Splashtop Business Access 屏幕远程控制软件 1年订阅 仅需 398 主控端设备不限,授权随账户,被控端数量屈居于购买的数量。
  6. 搜索引擎已死?ChatGPT访问量创新高:面前只剩三家
  7. popwindow 挡住 魅族手机虚拟按键
  8. 微信小程序开发(3) 热门电影
  9. 烟草零售市场检查“APCD”工作法具体是什么?
  10. 展锐平台userdebug版本关闭ylog