【问题标题】:Shuffling Algorithm Fair? (Javascript)洗牌算法公平? (Javascript)
【发布时间】:2016-08-17 07:05:02
【问题描述】:

我遇到了以下用于在 Javascript 中对数组进行洗牌的算法。它似乎与 Fisher-Yates shuffle 的不同之处在于可用“交换”的范围随着 for 循环计数器的增加而增加。这似乎与 Fisher-Yates 版本的行为方式相反。我很好奇这是否是一个有效的算法。是伪装的费雪耶茨吗?有偏见吗?

如果有人可以提供一些代码来测试它生成的排列频率,那将是一个奖励。

<script>
var shuffle = function (myArray) {
    var random = 0;
    var temp = 0;
    console.log(myArray);
    for (i = 1; i < myArray.length; i++) {
        random = Math.round(Math.random() * i);
        console.log(random + '\n');
        temp = myArray[i];
        myArray[i] = myArray[random];
        myArray[random] = temp;
        console.log(myArray);
    }
    return myArray;
}

var arr = [1, 2, 3, 4];

shuffle(arr);

</script>

【问题讨论】:

  • 你有没有测试过它是否有任何可观察到的偏差?
  • 那个随机的缩进,虽然...
  • is this a valid algorithm - 是的,它不会抛出任何错误。
  • 不确定如何编写程序来测试大量试验的所有排列。乍一看,结果“看起来”很公平,但我想要更多证据 - 阅读了关于洗牌的常见幼稚解决方案的严重偏见。
  • 使用Math.floor()而不是Math.round(),除此之外,算法很好而且很常见。 edit: 我知道的实现总是向后迭代;无法判断这是否有显着差异。

标签: javascript algorithm shuffle


【解决方案1】:

不,这不公平。

Math.random() * i 是介于 0 和 i 之间的统一随机浮点值,但 Math.round(Math.random() * i) 不会平等地选择介于 0 和 i 之间的整数。例如,i 为 2 时,[0, 0.5) 范围内的值舍入为 0,[0.5, 1.5) 范围内的值舍入为 1, (1.5, 2) 范围内的值舍入为 2 . 这意味着不是同样频繁地选择 0、1 和 2,而是以 0.5 的概率选择 1,并以 0.25 的概率分别选择 0 和 2。

Math.floor(Math.random * (i + 1)) 是正确的。

您可以通过统计方式验证这一点:将数组 [0, 1, 2] 随机播放 10000 次,然后查看 2 保留在数组末尾的频率。它应该在 3333 左右,但由于偏差,它会更像 2500。

除此之外,该算法是正确的并且可以被描述为反向的Fisher-Yates。你可以通过归纳证明它是正确的。 n=1 的基本情况是微不足道的。归纳步骤也相对简单:如果你有 n 个项目的均匀随机排列,然后在从 0 到 n+1 的均匀随机索引处插入第 n+1 个项目,那么你有一个随机排列n+1 项的排列。

【讨论】:

  • 好的,我接受地板与圆形部分。但是,如果使用地板,是否公平?事实上,交换头寸的范围从小到大,这似乎与费雪-耶茨完全不同。
  • @Robin 是的,我扩展了我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-28
  • 1970-01-01
  • 2017-07-08
  • 1970-01-01
相关资源
最近更新 更多