洗牌乱序算法

洗牌算法(Fisher-Yates),简单的思路如下:

  • 定义一个数组,以数组的最后一个元素为基准点。

  • 在数组开始位置到基准点之间随机取一个位置,将所取位置上的元素和基准点上的元素互换。

  • 基准点左移一位。

  • 重复2,3步骤,直到基准点为数组的开始位置。

Math.random:

  • 产生一个[0,1)之间的数

underscore在原生的Math.random()方法上,重新包装了random函数,实现在给定范围内生成随机整数,如果只传递一个参数,那么将返回0和这个参数之间的整数

// 随机函数
_.random = function (min, max) {
    if (max == null) { // max == null即代表只传递一个参数,此时最大值为传递的最小值,最小值为0
        max = min;
        min = 0;
    }
    return min + Math.floor(Math.random() * (max - min + 1)); // 生成[min, max]之前的随机数
};

underscore 1.9版本:

  • n则代表返回多少个随机数。同时list不仅可以是数组,也可以是对象或者类数组,当list为对象时,随机返回的是对象的值,如
console.log(_.sample({a: 123, b: 234}, 2)) // 234 123

实现代码:

_.sample = function(list, n) {
    if(n == null) { // 不指定个数时,默认在数组中随机取出一个。
        if (!isArrayLike(obj)) list = _.values(list); // list为对象时,取出对象值的集合。
        return list[_.random(list.length - 1)] // 生成数组的随机位置,返回该位置的值。
    }
    var sample = isArrayLike(obj) ? _.clone(obj) : _.values(obj); // 数组类数组得到克隆的数组,对象得到值的集合。
    var length = getLength(sample);
    n = Math.max(Math.min(n, length), 0); // 对n的大小做限制,不能大于新数组的长度,不能小于0。
    var last = length - 1;
    for (var index = 0; index < n; index++) { //  for循环下的操作为洗牌算法的核心步骤,和前面讲解的实现方式相同。
        var rand = _.random(index, last);
        var temp = sample[index];
        sample[index] = sample[rand];
        sample[rand] = temp;
    }
    return sample.slice(0, n);
}

underscore 1.8版本:

_.shuffle = function(obj) {
    var set = obj && obj.length === +obj.length ? obj : _.values(obj);
    var length = set.length;
    var shuffled = Array(length);
    for (var index = 0, rand; index < length; index++) {
      rand = _.random(0, index);
      if (rand !== index) shuffled[index] = shuffled[rand];
      shuffled[rand] = set[index];
    }
    return shuffled;
};

你可能感兴趣的:(前端算法,算法,leetcode,职场和发展)