洗牌算法公平? (JavaScript)的

时间:2016-08-17 07:05:03

标签: javascript algorithm shuffle

我遇到了下面的算法,用于在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>

1 个答案:

答案 0 :(得分:3)

不,这不是一个公平的洗牌。

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)这意味着不是同样经常选择0,1和2,而是以0.5的概率选择1,并且每次选取0和2,概率为0.25。

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

您可以统计验证:将数组[0,1,2]洗牌10000次,看看2在数组末尾保留的频率。应该是3333左右,但由于偏见,它会更像2500.

除此之外,该算法是正确的,可以反过来描述为Fisher-Yates。您可以通过归纳证明它是正确的。 n = 1的基本情况是微不足道的。归纳步骤也相对简单:如果您对n个项目进行了均匀随机排列,然后在0到n + 1的均匀随机索引处插入第n + 1个项目,那么您&# 39;我得到了n + 1项的随机排列。