Knuth shuffle 如下(在 Python 中,但可能是伪代码)
for i in range(len(v)):
swap(v, i, randrange(i, len(v))
naïve shuffle 非常相似,但它不是 Knuth shuffle:
for i in range(len(v)):
swap(v, i, randrange(0, len(v))
Knuth shuffle 产生均匀分布的排列。可以证明朴素 shuffle 不会,因为有 nn 个可能的随机数序列,每个序列具有相等的概率,并且n!可能的排列,这不是 nn 的因素。 (另一方面,Knuth shuffle 恰好涉及 n! 个可能的随机数序列,每个序列都可以被证明产生唯一的排列。)
上述证明并未表明朴素洗牌中的各个排列位置是否均匀分布。尽管如此,排列的非均匀分布仍有可能产生排列元素的均匀分布:例如,如果除了旋转之外的所有排列的概率为 0,并且旋转具有相等的概率,那么排列元素将是均匀分布的。 (这将是比天真的洗牌更糟糕的洗牌。)
事实证明,naïve shuffle 不会产生均匀分布的元素位置。有两点规律性:向量中第一个元素的最终位置是均匀分布的,最终到达最终位置的元素也是如此。
元素i(i≠0)最有可能的最终位置是i-1。
这是 n=8 的转移概率表,计算为转移矩阵的乘积:
from/to 0 1 2 3 4 5 6 7
0 .125 .125 .125 .125 .125 .125 .125 .125
1 .158 .116 .117 .118 .119 .121 .123 .125
2 .144 .151 .110 .112 .115 .118 .121 .125
3 .132 .139 .147 .107 .111 .115 .119 .125
4 .122 .129 .137 .146 .107 .112 .118 .125
5 .113 .120 .128 .137 .147 .110 .117 .125
6 .105 .112 .120 .129 .139 .151 .116 .125
7 .098 .105 .113 .122 .132 .144 .158 .125
可以推导出 Pn(i, j) -- n 个元素的向量中的元素 i 将被打乱到位置 j 的概率。
在算法中,迭代i时的swap涉及到元素vi sub> 和其他一些元素 vj。 (有可能 i=j。)虽然 swap 是一种对称操作,但区分这两个元素是有用的;我们称之为元素 vi 的 out swap 和 in swap em> 的 vj
注意在元素k的in swap之后,k不能再out swapped,因为以下所有 out swaps 都位于 k 的新位置之后的位置。因此,如果 k 曾经交换出,则它必须在迭代 k 时交换出;换句话说,只有第一个涉及元素的交换可以在 out swap。
现在,在洗牌的任何一次迭代中,即将换出的元素的最终目的地都是均匀分布的。 (最终目的地为 j 的概率是下一个位置为 i 的概率乘以所有 i 的概率之和下一个位置i的最终目的地为j。由于下一个位置是均匀分布的,因此可以将乘数因式分解,剩余的和为1,因为j 必须来自某个 i。)
另外,对于一个从不out swapped的元素,它的最终目的地是它最后一次in swap发生的迭代。 (一个元素不可能既不是out swapped也不是in swapped。如果元素在in swap发生>out swap 位置,它将被out swapped。)
有了这些,我们就可以推导出转移函数的公式了。
首先,元素 k 将被交换出 的概率正是它在任何迭代中不交换 的概率在k之前,即(n-1)k/nk。在 k 被交换的洗牌中,最终目的地是均匀分布的,所以这贡献了 (n−1)k/nk+1 到每个转移概率Pn(k, j).
现在让我们考虑最后一个in swap 是在迭代j 的情况(因此是位置j)。在每次迭代中,给定元素将以 1/n 的概率交换。因此,最后一个 in swap 在迭代 j 的概率是在 j 之后没有发生交换的概率乘以发生交换的概率在迭代j,即(n-1)n-j-1/nn-j.
如果jk,那么k不能换出,但是如果j≥k,我们只需要计算在迭代k之前有交换的情况。这导致了以下定义:
Pn(k, j) = ( n-1)k/nk+1 + (1−On(k, j))×(n-1)nj-1/nn-j支持>
在哪里
On(k, j) = 0 如果 jk,否则 (n-1)k/n k