Fisher–Yates shuffle洗牌算法

背景

如何将一个数组中的元素随机打乱?
如何又却能确保一个元素的位置不变,将其他元素位置打乱?

问题:用js实现一个随机打乱数组顺序的函数,要求可以设定数组种任意1个元素的位置不变,其他位置的元素位置随机变化。

基本思路

先理解出基本的洗牌算法,将一个数组全部打乱,再在这个基础上增添条件。

需要设置一个下标的数字不变,基本思路:

  1. 首先判断下标数字是合法的,即传入的数组中有该下标;
  2. 在for循环时,当遍历到指定的index时,应当跳过此次循环;
  3. 在生成随机数时,应当保证 生成的随机数 !== index;

解决

首先我们先不考虑可以设定数组任意一个元素的位置不变这一条件,直接先考虑如何打乱一个数组。

利用Fisher–Yates shuffle算法

Array.prototype.shuffle = function() {

  const arr = this;
  
  for (let i = arr.length -1; i >= 0; i--) {
    
    // 获取随机数
    const randomIndex = Math.floor(Math.random() * (i + 1));
    // 交换值
    [arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]];
    
  }
  
  return arr;
};

然后我们在增加条件,可以设定数组中任意1个元素的位置不变。

function shuffleWithoutIndex(arr, index) {
  
  if (typeof arr === undefined) return;
  if (typeof index === undefined) return;
  
  if (index < 0 || index > arr.length -1) {
    return;
  }
  
  const array = arr;
  
  for (let i = array.length - 1; i >= 0; i--) {
    
    // 跳过需要固定的那个元素
    if (i === index) { continue; }
    
    let randomIndex = -1;
    // 获取随机数,保证随机数不等于需要固定的index
    do {
      randomIndex = Math.floor(Math.random() * (i + 1));
    } while(randomIndex === index);
   
    // 交换值
    [array[i], array[randomIndex]] = [array[randomIndex], array[i]];
    
  }
  
  return array;
}

参考资料

洗牌算法介绍-维基百科
洗牌算法实现
Math.random()-MDN

你可能感兴趣的:(Fisher–Yates shuffle洗牌算法)