之前被问问题的时候,问到如何讲一个数组打乱,当时也不由思索说出了一个比较常用的方式,也可以说是我目前接触到最精简的方式:
function randomsort(a, b) {
return Math.random()>0.5 ? -1 : 1;
}
这里介绍下sort()函数,在JS中Array对象里内置了一个函数:
array.sort(sortfunction)
此方法将 Array 对象进行适当的排序;在执行过程中并不会创建新的 Array 对象。
如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以便进行比较。
如果想按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。比较函数应该具有两个参数
a 和 b,其返回值如下:● 若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
● 若 a 等于 b,则返回 0。
● 若 a 大于 b,则返回一个大于 0 的值。
为什么通过比较就可以达到排序的目的?sort内部原理就是冒泡排序:
冒泡排序算法的原理如下(升序):
①比较相邻的元素。如果第一个比第二个大,就交换他们两个。
②对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
③针对所有的元素重复以上的步骤,除了最后一个。
④持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
但是同时又被问到这样够不够乱?
我思考甚久,乱的定义是什么?——“每一个数字在每一个位置上的概率是一样的,或者说每一个位置上出现所有中每一个数字的概率是一样的”
对于sort()方法而言,每次利用不定的前后置换的方式,可能还没办法达到这种程度。
试试洗牌算法:
Array.prototype.shuffle = function () {
let arr = this;
for (let i = arr.length - 1; i >= 0; i--) {
//取得0~i的整数
let randomIndex = Math.floor(Math.random() * (i + 1));
//得到任意index 的值
let itemAtIndex = arr[randomIndex];
//交换
arr[randomIndex] = arr[i];
arr[i] = itemAtIndex;
}
return arr;
}
——————————来源博客:https://www.jb51.net/article/81373.htm————————
看完代码之后,让我们看看它对数组都做了写什么。首先,该方法选中数组的最后一个元素:
接下来确定挑选随机元素的范围,从数组的第一个元素到上一步选中的元素都属于这一范围:
确定范围后,从中随机挑选一个数,这里假设随机选中的元素为 4:
然后交换最后一个元素和随机选中的元素的值:
上面的交换完成后,相当于我们完成了对数组最后一个元素的随机处理。接下来选中数组内倒数第二的元素:
之所以从后往前处理,是因为这样便于确定随机选择的范围。这次我们假定随机到的元素为 2:
接着交换倒数第一个元素和 2 号元素的值,完成对倒数第二个元素随机排列的处理。然后是选中倒数第三个元素,重复之前的操作:
————————————————————————————————————————
测试数组:
arr=[1,2,3,4,5,6,7,8,9,10,11,12]
进行两种方法比较的方式是:对每个方法设立一个结果数组,长度为12,初始化为0,每个位置代表这个index上的所有排序后出现的值的和,我们将进行10000次无记忆乱序,每次对12个index上的数字进行加法运算,如此10000次,如果足够乱序(每个位置出现每个数字的概率是相同的),那么最终每个位置的10000次加法后的和会趋于一致,波动不会太大。
Array.prototype.addArr = function(arr2){
let arr=this
let len=arr.length
for(let i=0;i<len;i++){
arr[i]=arr[i]+arr2[i]
}
}
let result=new Array(12).fill(0)
for(let i=0;i<=10000;i++){
let curResult=arr.concat().shuffle()
result.addArr(curResult)
}
console.log('洗牌算法方法: \n'+result)
let result2=new Array(12).fill(0)
for(let i=0;i<=10000;i++){
let curResult=arr.concat().sort(randomsort);
result2.addArr(curResult)
}
console.log('sort()方法: \n'+result2)
var variance = function(numbers) {
var mean = 0;
var sum = 0;
for(var i=0;i<numbers.length;i++){
sum += numbers[i];
}
mean = sum / numbers.length;
sum = 0;
for(var i=0;i<numbers.length;i++){
sum += Math.pow(numbers[i] - mean , 2);
}
return sum / numbers.length;
};
console.log("洗牌算法方法的方差: "+variance(result))
console.log("sort()方法的方差: "+variance(result2))