洗牌算法

洗牌算法

Fisher-Yates Shuffle

Fisher–Yates 隨機置亂算法,通俗說就是生成一個有限集合的隨機排列。算法

描述:數組

  • 寫下從 1 到 N 的數字
  • 取一個從 1 到剩下的數字(包括這個數字)的隨機數 k
  • 從低位開始,獲得第 k 個尚未被取出的數字,把它寫在獨立的一個列表的最後一位
  • 重複第 2 步,直到全部的數字都被取出
  • 第 3 步寫出的這個序列,如今就是原始數字的隨機排列
function getRandom(arr, length) {
  const random = Math.floor(Math.random() * length)

  // 原始算法將在此處消耗較多資源
  if (arr.includes(random)) {
    return getRandom(arr, length)
  } else {
    return random
  }
}

function randomArray(arr) {
  let newArr = []
  const length = arr.length
  let index = length - 1
  let indexArr = []
  while (index >= 0) {
    const random = getRandom(indexArr, length)
    indexArr.push(random)
    newArr.push(arr[random])
    --index
  }

  return newArr
}

Knuth-Durstenfeld Shuffle

Knuth 和  Durstenfeld   在 Fisher 等人的基礎上對算法進行了改進,不借助新的組數,直接在原地交換。該算法的基本思想和 Fisher 相似,每次從未處理的數據中隨機取出一個數,並和最後一個剩餘元素交換,而後剩餘元素的數量減一。dom

function randomArray(arr) {
  const length = arr.length
  for (let index = length - 1; index > 0; index--) {
    const random = Math.floor(Math.random() * index)
    const temp = arr[index]
    arr[index] = arr[random]
    arr[random] = temp
  }

  return arr
}

Inside-Out Algorithm

Inside-Out Algorithm 算法的思想是從前日後,藉助舊數組,將新數組中位置 k 和位置 i 的數字進行交互ide

描述.net

  • 拷貝數組
  • 從 i(0 - N)掃描數組,選擇一個隨機數 k( 0 <= k <= i)
  • 新數組的[i] = 新數組的[k], 新數組的[k] = 原始數組[i]
  • 重複第 2 步,直到末尾
  • 最終的新數組就是隨機的
function randomArray(arr) {
  let newArr = arr.concat([])
  const length = arr.length
  for (let index = 0; index < length; index++) {
    const random = Math.floor(Math.random() * (index + 1))
    newArr[index] = newArr[random]
    newArr[random] = arr[index]
  }

  return newArr
}

參考

相關文章
相關標籤/搜索