数组随机排序之洗牌
@Traveller在DIV.IO分享了一篇《数组元素随机化排序算法实现》,这篇文章提供了三种数组项随机排序的实现方法:
使用数组sort方法对数组元素随机排序
1 Array.prototype.shuffle = function(n) { 2 var len = this.length , 3 num = n ? Math.min(n,len) : len, 4 arr = this.slice(0); 5 arr.sort(function(a,b){ 6 return Math.random()-0.5; 7 }); 8 return arr.slice(0,num-1); 9 }
随机交换数组内的元素
1 lib = {} 2 lib.range = function(min,max) { 3 return min + Math.floor(Math.random()*(max-min+1)); 4 } 5 6 Array.prototype.shuffle = function(n) { 7 var len = this.length, 8 num = n ? Math.min(n,len) : len, 9 arr = this.slice(0), 10 temp, 11 index; 12 13 for (var i=0;i<len;i++){ 14 index = lib.range(i,len-1); 15 temp = arr[i]; 16 arr[i] = arr[index]; 17 arr[index]=temp; 18 } 19 return arr.slice(0,num); 20 }
随机从原数组抽取一个元素,加入到新数组
1 lib = {} 2 lib.range = function(min,max) { 3 return min+Math.floor(Math.random()*(max-min+1)); 4 } 5 6 Array.prototype.shuffle = function(n) { 7 var len = this.length, 8 num = n ? Math.min(n,len) : len, 9 arr = this.slice(0), 10 result=[], 11 index; 12 13 for (var i=0;i<num;i++){ 14 index = lib.range(0,len-1-i); 15 // 或者 result.concat(arr.splice(index,1)) 16 result.push(arr.splice(index,1)[0]); 17 } 18 return result 19 }
洗牌算法
数组随机排序其基本原理是洗牌算法(Fisher–Yates shuffle):
是一种将有限集合的顺序打乱的一种算法
原理
- 定义一个数组(
shuffled
),长度(length
)是原数组(arr
)长度 - 取
0
到index
(初始0
) 随机值rand
,shuffled[index] = shuffled[rand]
,shuffled[rand] = arr[index]
index++
; 重复第二步,直到index = length -1
就是 shuffled
从 0
到 length-1
的赋值过程,并且新加入的值是 arr[index]
,shuffled[index]
的值是已赋值的元素中随机值shuffled[rand]
,因为这样会有两个重复的值,所以 shuffled[rand]
就等于新加入的值 arr[index]
underscore.js
中的 shuffle
方法
1 function random(min, max) { 2 if (max == null) { 3 max = min; 4 min = 0; 5 } 6 return min + Math.floor(Math.random() * (max - min + 1)); 7 }; 8 function shuffle(arr) { 9 var length = arr.length, 10 shuffled = Array(length); 11 for (var index = 0, rand; index < length; index++) { 12 rand = random(0, index); 13 if (rand !== index) shuffled[index] = shuffled[rand]; 14 shuffled[rand] = arr[index]; 15 } 16 return shuffled; 17 }
实际运用:
1 var arr = [1,2,3,4,5,6,7,8,9]; 2 for (var i = 0; i < 10; i++){ 3 console.log(shuffle(arr)); 4 }
Chrome输出的结果如下:
还有更简单易理解的写法:
1 function shuffle(arr) { 2 var i, 3 j, 4 temp; 5 for (i = arr.length - 1; i > 0; i--) { 6 j = Math.floor(Math.random() * (i + 1)); 7 temp = arr[i]; 8 arr[i] = arr[j]; 9 arr[j] = temp; 10 } 11 return arr; 12 };
有关于洗牌算法扩展阅读
- Fisher–Yates shuffle
- Shuffling an Array in JavaScript
- Fisher–Yates Shuffle
- 如何测试洗牌程序
- Fisher-Yates-shuffle洗牌算法
- How to randomize (shuffle) a JavaScript array?