JavaScript-数组乱序

前言

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

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

欢迎关注我的微信公众号:前端极客技术(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)

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/256321.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序:Array数组的操作

Array 对象方法 方法描述concat()连接两个或更多的数组&#xff0c;并返回结果。copyWithin()从数组的指定位置拷贝元素到数组的另一个指定位置中。entries()返回数组的可迭代对象。every()检测数值元素的每个元素是否都符合条件。fill()使用一个固定值来填充数组。filter()检…

js 数组排序

代码改变世界 Posts - 29, Articles - 0, Comments - 62 Cnblogs Dashboard Login HOMECONTACTGALLERYRSS 那时候的我github&#xff1a;https://github.com/lwzhang js中的数组对象排序 2014-04-27 19:15 by 那时候的我, 66416 阅读, 2 评论, 收藏, 编辑 一、普通数组排序…

微信小程序——数组操作 (增加删除修改遍历)map、filter、forEach、find的用法、二维数组,排序,求和、指定长度数组赋值

一、数组的操作 Array.push() ->在数组后面继续插入内容 Array.pop() ->拿走数组最后一个内容 Array…shift()->拿走数组的第一个内容 (unshift也是拿走最后一个) Array.reverse()->对数组从大到小排列 Array.sort()->对数组从小到大排列** Array.splice(起始…

js数组排序实用方法集锦

js数组排序实用方法集锦 前言&#xff1a; 据说程序员三个月就能忘记自己写的代码&#xff0c;所以最好是在有空的时候及时做些总结&#xff0c;记录下来&#xff0c;这样后边遇到类似问题的话&#xff0c;就可以直接先查看自己的博客了。写技术博客&#xff0c;对自己是一种总…

运行 100 万个并发任务究竟需要多少内存?

Laf 公众号已接入了 AI 绘画工具 Midjourney&#xff0c;可以让你轻松画出很多“大师”级的作品。同时还接入了 AI 聊天机器人&#xff0c;支持 GPT、Claude 以及 Laf 专有模型&#xff0c;可通过指令来随意切换模型。欢迎前来调戏&#x1f447; <<< 左右滑动见更多 &…

MyBatis 环境搭建+基本使用

目录 MyBatis创建MyBatis环境搭建MyBatis模式开发MyBatis 获取动态参数&#xff08;查询操作&#xff09;${} 直接替换#{} 占位符模式替换like查询&#xff08;模糊查询&#xff09;多表查询一对一的表映射一对多的表映射 增、删、改操作改操作删除操作增加操作添加用户添加用户…

Spring事务与事务传播

文章目录 一、什么是事务?二、Spring事务实现编程式事务声明式事务 三、Transactional的使用参数作用Spring事务的隔离级别事务失效的场景Transactional工作原理 四、Spring事务传播机制Spring有哪些事务传播机制&#xff1f; 一、什么是事务? 事务&#xff1a;事务是一组操…

mybatis分页中的报错

1 Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.NoSuchMethodException: com.github.pagehelper.BoundSqlInterceptor.<init>() 出错的原因就是上面的那句话 Error parsing SQL Mapper Configuration…

Mybatis分页方式及实现原理

一、mybatis的4种分页方式(物理分页、逻辑分页) 1、借助Sql语句Q进行分页(物理分页) 2、拦截器分页(物理分页)通过拦截器给sq语句末尾加Eimt语句来查询 3、借助 数组Q进行分页(逻辑分页) 4、RowBounds分页插件实现分页(逻辑分页) 二、mybatis分页的原理 mybatis分页原理是&…

Ora提示词版ChatGPT机器人

Ora可以自己创建一个ChatGPT机器人&#xff0c;可以设置自己的提示词例如我创建的AI佛祖https://ora.ai/aesthetic-red-nfa4/ai%E4%BD%9B%E7%A5%96 提示词 创建机器人的时候&#xff0c;需要设定自己的提示词&#xff0c;例如&#xff1a; 假设你是佛祖&#xff0c;名字叫做释迦…

mybatis分页查询插件

1.引入jar包 <dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.3.0</version></dependency> 2.在mybatis的核心配置文件mybatis.xml中配置分页插件 3.使用pageHec publi…

Mybatis分页查询——四种传参方式

目录 相关导读 一、顺序传参 1. 持久层接口方法 2. UserMapper.xml映射文件新增标签 3. 新增测试方法 4. 运行结果 二、param传参 1. 持久层接口方法 2. UserMapper.xml映射文件新增标签 3. 新增测试方法 4. 运行结果 三、自定义POJO类传参 1. 自定义POJO类 2. 持…

MyBatis分页插件

目录 分页插件 Mybatis插件典型适用场景 实现思考 第一个问题 第二个问题 自定义分页插件 分页插件使用 添加pom依赖 插件注册 调用 代理和拦截是怎么实现的 PageHelper 原理 分页插件 MyBatis 通过提供插件机制&#xff0c;让我们可以根据自己的需要去增强MyBati…

Mybatis——分页

1.为什么要分页&#xff1f; 减少数据的处理量使用Limit分页 select * from user limit startIndex,pageSize;使用Mybatis实现分页&#xff0c;核心SQL 1.数据库文件-db.properties drivercom.mysql.jdbc.Driver urljdbc:mysql://localhost:3306/mybatis?useSSLfalse&…

Mybatis实现分页的三种方式

文章目录 1、Limit实现分页2、RowBounds分页&#xff08;不建议使用&#xff09;3、MyBatis分页插件PageHelper&#xff08;了解即可&#xff09; 1、Limit实现分页 sql语句 SELECT * from user limit startIndex,pageSize简单示例&#xff1a; user表 查询一&#xff1a;从第…

Mybatis的四种分页方式详解

LIMIT关键字 mapper代码 select * from tb_user limit #{pageNo}, #{pageSize} 业务层直接调用 public List findByPageInfo(PageInfo info) { return userMapper.selectByPageInfo(info); } 3&#xff0c;优点 灵活性高&#xff0c;可优化空间大 mysql分页语句优化 4&…

mybatis实现分页的几种方式

本文目录 借助数组进行分页借助Sql语句进行分页拦截器分页RowBounds实现分页 借助数组进行分页 原理&#xff1a;进行数据库查询操作时&#xff0c;获取到数据库中所有满足条件的记录&#xff0c;保存在应用的临时数组中&#xff0c;再通过List的subList方法&#xff0c;获取到…

【分布式应用】ELK企业级日志分析系统

一、ELK 简介 ELK平台是一套完整的日志集中处理解决方案&#xff0c;将 ElasticSearch、Logstash 和 Kiabana 三个开源工具配合使用&#xff0c; 完成更强大的用户对日志的查询、排序、统计需求。 1.1 ELK各组件介绍 ElasticSearch&#xff1a; 是基于Lucene&#xff08;一个…

Rust每日一练(Leetday0016) 全排列I\II、旋转图像

目录 46. 全排列 Permutations &#x1f31f;&#x1f31f; 47. 全排列 II Permutations II &#x1f31f;&#x1f31f; 48. 旋转图像 Rotate Image &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专…

win10操作系统官网如何下载ios境像文件安装操作系统

1.打开官网 2.立即下载工具 3.正在准备进行工作 4.接收条款 5.根据需求选择安装合适的位置 6.等待创建成功 7.右键选择装载 8.双击安装setup.exe文件 8 使用微Pe安装过程中发现需要联网更新解决 winR 然后cmd 输入 OOBE\BYPASSNRO 9 或者关闭此进程 电脑不要插网线&#xff…