Fisher-Yates 洗牌算法

Fisher-Yates 洗牌算法(也称为 Knuth 洗牌)是一种高效且公正的随机洗牌算法,用于将数组或列表中的元素随机重新排列。

🎯 算法原理

核心思想:从后往前遍历数组,将当前元素与随机位置的一个元素交换。

📝 算法步骤

原始版本:

// 从后往前遍历
for i from n-1 down to 1 do:
j = 随机整数 (0 ≤ j ≤ i)
交换 array[i] 和 array[j]

现代版本(Knuth 改进):

// 从前往后遍历(更直观)
for i from 0 to n-2 do:
j = 随机整数 (i ≤ j ≤ n-1)
交换 array[i] 和 array[j]

🔢 示例演示

假设数组:[1, 2, 3, 4, 5]

步骤:

  1. i=0: j=随机(0-4),假设 j=2 → 交换 arr[0] 和 arr[2]
    • 数组变为:[3, 2, 1, 4, 5]
  2. i=1: j=随机(1-4),假设 j=3 → 交换 arr[1] 和 arr[3]
    • 数组变为:[3, 4, 1, 2, 5]
  3. i=2: j=随机(2-4),假设 j=2 → 无交换
    • 数组保持:[3, 4, 1, 2, 5]
  4. i=3: j=随机(3-4),假设 j=4 → 交换 arr[3] 和 arr[4]
    • 最终结果:[3, 4, 1, 5, 2]

💻 代码实现

PHP 实现:

function fisherYatesShuffle(array &$array): void
{
$count = count($array);
for ($i = $count - 1; $i > 0; $i--) {
$j = random_int(0, $i); // 生成 0 到 i 的随机整数
[$array[$i], $array[$j]] = [$array[$j], $array[$i]];
}
}

// 使用示例
$girds = [1, 2, 3, 4, 5];
fisherYatesShuffle($girds);

JavaScript 实现:

function fisherYatesShuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}

✅ 算法优势

  1. 均匀分布:每个排列出现的概率相等
  2. 时间复杂度:O(n) - 非常高效
  3. 空间复杂度:O(1) - 原地操作
  4. 无偏性:真正的随机洗牌

❌ 对比其他方法的劣势

错误方法示例:

// ❌ 错误:非均匀分布
array.sort(() => Math.random() - 0.5);

// ❌ 错误:可能重复交换,效率低
for (let i = 0; i < array.length; i++) {
const j = Math.floor(Math.random() * array.length);
[array[i], array[j]] = [array[j], array[i]];
}

Fisher-Yates 是洗牌算法的黄金标准,在需要真正随机排列时应该优先选择它。


文章作者: Crazy Boy
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Crazy Boy !
赏

留言

想法、疑问或勘误,都可以写在这里。留言会公开显示。

正在准备留言区…

 上一篇
锁步协议(Lockstep):RTS游戏的完美同步之道 锁步协议(Lockstep):RTS游戏的完美同步之道
如何让数百个作战单位在多个玩家间保持精确同步?锁步协议通过确定性仿真和命令同步,为实时战略游戏提供了完美的网络同步解决方案。 问题背景 在实时战略游戏(RTS)中,网络同步面临独特挑战: 大规模单位:数百个作战单位需要同步状态 精确时序:技
2025-11-20
下一篇 
加权随机算法:按权重控制的概率选择机制 加权随机算法:按权重控制的概率选择机制
如何让稀有物品掉落率低、普通物品掉落率高?加权随机算法提供了完美的概率控制方案。 问题背景 在很多应用场景中,我们需要按照预设的概率分布来进行随机选择,而不是简单的均匀随机: 游戏开发:稀有装备1%概率,普通装备50%概率 推荐系统:热门商
2025-11-20