Javascript算法 — 数组乱序(洗牌算法)
本文介绍js中几种洗牌算法。
洗牌算法是将原来的数组进行打散,使原数组的某个数在打散后的数组中的每个位置上等概率的出现,即为乱序算法。
Fisher-Yates
先看最经典的
Fisher-Yates
的洗牌算法
其算法思想就是从原数组中随机抽取一个元素放入新数组
- 从原数组(假如长度为n)中,随机生成一个索引 random
- 从原数组中删除第 random 个元素并将其push到新数组
- 重复第2步直到所有元素取完
- 最终得到一个新的打乱的数组
按步骤一步一步来就很简单的实现。
1 | const shuffle1 = arr => { |
这种算法要去除原数组 arr 中的元素,所以时间复杂度为 O(n2)
Knuth-Durstenfeld ShuffleFisher-Yates
洗牌算法的一个变种是 Knuth Shuffle
每次从原数组中随机取一个元素,然后把该元素跟最后一个元素交换,即数组的尾部放的是已经处理过的元素
这是一种原地打乱的算法,不会产生新的数组,每个元素随机概率也相等,时间复杂度从 Fisher 算法的 O(n2)提升到了 O(n)
- 假设原数组长度为n,生成一个0~n-1的随机数random,然后将第random个元素跟数组最后一个元素交换
- 生成一个0~n-2的随机数random,然后将第random个元素跟数组倒数第二个元素交换
- 以此类推,直到交换结束为止
1 | const shuffle2 = arr => { |
Durstenfeld Shuffle的算法是随机产生一个数从后往前交换,和Knuth的区别是方向的不同。
sort
利用Array的sort方法可以更简洁的实现打乱,对于数量小的数组来说足够。因为随着数组元素增加,随机性会变差。
随机返回-0.5到0.5的值,数组顺序进行随机交换,就实现了洗牌,也可以理解为数组排序规则不固定,穿插从大到小或者从小到大,从而实现随机。
1 | const shuffle3 = arr => arr.sort(() => 0.5 - Math.random()) |
ES6
Knuth-Durstenfeld shuffle 的 ES6 实现,利用位运算符,代码更简洁
1 | const shuffle4 = arr => { |
lodash
可以使用lodash里面的_.shuffle(collection)
方法
参数
collection
(Array|Object): 要打乱的集合。
返回
(Array): 返回打乱的新数组。
例子
1 | var _ = require('lodash') |
代码不是万能的,但不写代码是万万不能的
Dary记
-
更多干货,尽在公众号
转载请注明来源,文末有原始链接。欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 dary1112@foxmail.com
创作不易,您的打赏是我更新的动力
-
支付宝
-
微信
文章标题:Javascript算法 — 数组乱序(洗牌算法)
文章字数:834
本文作者:Dary
发布时间:2021-01-25, 19:32:00
最后更新:2021-01-25, 15:25:30
原始链接:http://www.xiongdalin.com/2021/01/25/array-shuffle/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。
Built By Dary