我做了一些关于随机排序结果的随机性度量...
我的技术是取一个小数组 [1,2,3,4] 并创建所有的排列组合(4!= 24)。接着,我会对这个数组应用洗牌函数多次,并计算每个排列被生成的次数。好的洗牌算法会将结果相当均匀地分布在所有排列上,而糟糕的算法则不会创造出那种均匀的结果。
使用下面的代码我在 Firefox、Opera、Chrome、IE6/7/8 中进行了测试。
令我惊讶的是,随机排序和真实的洗牌都创造出了同样均匀的分布。因此,看来(正如许多人所建议的),大多数浏览器都在使用归并排序。当然,这并不意味着可能没有某个浏览器表现不同,但我会说这意味着这种随机排序方法在实践中足够可靠。
编辑:这个测试没有正确衡量随机性或缺乏随机性。请参考我发布的另一个答案。
但在性能方面,由 Cristoph 提供的洗牌函数是显而易见的赢家。即使对于小型四元素数组,真正的洗牌的执行速度也是随机排序的两倍左右!
```javascript
// Cristoph 发布的洗牌函数。
var shuffle = function(array) {
var tmp, current, top = array.length;
if(top) while(--top) {
current = Math.floor(Math.random() * (top + 1));
tmp = array[current];
array[current] = array[top];
array[top] = tmp;
}
return array;
};
// 随机排序函数
var rnd = function() {
return Math.round(Math.random())-0.5;
};
var randSort = function(A) {
return A.sort(rnd);
};
var permutations = function(A) {
if (A.length == 1) {
return [A];
}
else {
var perms = [];
for (var i=0; i<A.length; i++) {
var x = A.slice(i, i+1);
var xs = A.slice(0, i).concat(A.slice(i+1));
var subperms = permutations(xs);
var permutations = function(A) {
if (A.length === 0)
return [[]];
else {
var perms = [];
for (var i=0; i<A.length; i++) {
var x = A[i];
var subperms = permutations(A.slice(0,i).concat(A.slice(i+1)));
for (var j=0; j<subperms.length; j++) {
perms.push(x.concat(subperms[j]));
}
}
return perms;
}
};
var test = function(A, iterations, func) {
// 初始化排列
var stats = {};
var perms = permutations(A);
for (var i in perms){
stats[""+perms[i]] = 0;
}
// 洗牌多次并收集统计数据
var start=new Date();
for (var i=0; i<iterations; i++) {
var shuffled = func(A);
stats[""+shuffled]++;
}
var end=new Date();
// 格式化结果
var arr=[];
for (var i in stats) {
arr.push(i+" "+stats[i]);
}
return arr.join("\n")+"\n\n花费时间: " + ((end - start)/1000) + " 秒.";
};
alert("随机排序: " + test([1,2,3,4], 100000, randSort));
alert("洗牌: " + test([1,2,3,4], 100000, shuffle));