JavaScript的乱序算法【可视化比较】

1.sort()方法

之前被问问题的时候,问到如何讲一个数组打乱,当时也不由思索说出了一个比较常用的方式,也可以说是我目前接触到最精简的方式:

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内部原理就是冒泡排序

冒泡排序算法的原理如下(升序):
①比较相邻的元素。如果第一个比第二个大,就交换他们两个。
②对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
③针对所有的元素重复以上的步骤,除了最后一个。
④持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

2.洗牌算法

但是同时又被问到这样够不够乱?
我思考甚久,乱的定义是什么?——“每一个数字在每一个位置上的概率是一样的,或者说每一个位置上出现所有中每一个数字的概率是一样的”
对于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————————

看完代码之后,让我们看看它对数组都做了写什么。首先,该方法选中数组的最后一个元素:
在这里插入图片描述

接下来确定挑选随机元素的范围,从数组的第一个元素到上一步选中的元素都属于这一范围:
JavaScript的乱序算法【可视化比较】_第1张图片

确定范围后,从中随机挑选一个数,这里假设随机选中的元素为 4:

JavaScript的乱序算法【可视化比较】_第2张图片

然后交换最后一个元素和随机选中的元素的值:

JavaScript的乱序算法【可视化比较】_第3张图片

上面的交换完成后,相当于我们完成了对数组最后一个元素的随机处理。接下来选中数组内倒数第二的元素:
在这里插入图片描述

之所以从后往前处理,是因为这样便于确定随机选择的范围。这次我们假定随机到的元素为 2:

JavaScript的乱序算法【可视化比较】_第4张图片

接着交换倒数第一个元素和 2 号元素的值,完成对倒数第二个元素随机排列的处理。然后是选中倒数第三个元素,重复之前的操作:

在这里插入图片描述
————————————————————————————————————————

3.乱序比较

测试数组:

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))

JavaScript的乱序算法【可视化比较】_第5张图片

【结果可视化】
JavaScript的乱序算法【可视化比较】_第6张图片

你可能感兴趣的:(前端)