Knuth 将一个优雅的算法归功于 AJ Walker(Electronics Letters 10, 8 (1974), 127-128;ACM Trans. Math Software 3 (1977), 253-256)。
这个想法是,如果你总共有 n 个不同颜色的 k * n 个球,那么可以将这些球分布在 n 个容器中,这样容器号就可以了。i 包含颜色 i 和最多一种其他颜色的球。证明是对 n 的归纳。对于感应步骤,选择球数最少的颜色。
在您的示例中,n = 10。将概率与合适的 m 相乘,使它们都是整数。所以,也许 m = 100,你有 20 个颜色为 0 的球,20 个颜色为 1 的球,10 个颜色为 2 的球,5 个颜色为 3 的球,等等。所以,k = 10。
现在生成一个维度为 n 的表格,其中每个条目是概率(颜色 i 与另一种颜色的球的比率)和另一种颜色。
要生成一个随机球,请在 [0, n) 范围内生成一个随机浮点数 r。令 i 为整数部分(r 的下限),x 为多余部分(r - i)。
if (x < table[i].probability) output i
else output table[i].other
该算法的优势在于,对于每个随机球,您只需进行一次比较。
让我举一个例子(与 Knuth 相同)。
考虑模拟掷一对骰子。
所以 P(2) = 1/36, P(3) = 2/36, P(4) = 3/36, P(5) = 4/36, P(6) = 5/36, P(7) = 6/36, P(8) = 5/36, P(9) = 4/36, P(10) = 3/36, P(11) = 2/36, P(12) = 1/36。
乘以 36 * 11 得到 393 个球,11 个颜色 2,22 个颜色 3,33 个颜色 4,……,11 个颜色 12。我们有 k = 393 / 11 = 36。
表[2] = (11/36, 颜色 4)
表[12] = (11/36, 颜色 10)
表[3] =(22/36,颜色 5)
表[11] = (22/36, 颜色 5)
表[4] =(8/36,颜色 9)
表[10] = (8/36, 颜色 6)
表[5] =(16/36,颜色 6)
表[9] =(16/36,颜色 8)
表[6] =(7/36,颜色 8)
表[8] =(6/36,颜色 7)
表[7] = (36/36, 颜色 7)