关键词:数组乱序 Knuth算法 Fisher–Yates shuffle 洗牌算法
洗牌算法是棋牌游戏常用的一种算法,如上面关键词所列举的有好多种不同的叫法。主要解决的问题是: 1.保证数组元素享有同等的排序概率。2.保证排序的效率。
思路:
原始数组是 [1,2,3,4,5,7] , 通过洗牌算法让顺序全部打乱。
注:为了避免连续数字数组的错误理解,这里将第6个元素改成了7。
第一步:如何确定先移动哪一个元素? 随机数做索引就是个不错的办法。
第二步:已排过序的元素就不要动了,让每个元素享有同等的排序权。这就要求索引最大值每次都减1。
第二步:数组排序时要求数组大小不能变,这就要求主动移动元素和目标位置的元素做一个位置交换,这样就可以保证数组大小固定不变。
实现:
有了以上关键思路下面就来实现一下这个洗牌算法。
function shuffle(arr) {
for (let i=arr.length-1; i>=0; i--) {
let rIndex = Math.floor(Math.random()*(i+1));
let temp = arr[rIndex];
arr[rIndex] = arr[i];
arr[i] = temp;
}
return arr;
}
shuffle([1,2,3,4,5,7]);
// 结果:1 5 3 7 4 2
过程分析
这个过程很清晰,只要六次排序,整个数组就完全乱序了,这是随机+二分+交换的综合作用完成的一个排序。
| 随机数范围(剩余待排元素数量)→ | 随机数 → | 原始数据(待排) → | 结果(已排) |
|---|---|---|---|
| 1 2 3 4 5 7 | |||
| [ 0 , 5 ] | 1 | 1 7 3 4 5 | 2 |
| [ 0 , 4 ] | 3 | 1 7 3 5 | 4 2 |
| [ 0 , 3 ] | 1 | 1 5 3 | 7 4 2 |
| [ 0 , 2 ] | 2 | 1 5 | 3 7 4 2 |
| [ 0 , 1 ] | 1 | 1 | 5 3 7 4 2 |
| [ 0 , 0 ] | 0 | 1 5 3 7 4 2 |
经典的算法很香呀, 即保证公平性又兼顾效率的一个小算法。
拓展:
- underscore提供了一个shuffle算法
- 这里有个动画演示洗牌算法的过程
算法在面试中的作用
面试复试我认为分成三大部分内容:1.JS基础知识;2.算法;3.实践经验。
通过实践经验可以综合考察能力,其中就包含算法,而算法一定会包含基础知识点。并且基础知识点一定是通过算法才能真正的掌握,对于工作和面试都是非常重要的。