1

我正在使用此代码使用 Fisher-Yates 随机化算法的变体生成向量的随机排列(我从第一个元素到最后一个元素,而不是相反)。我在程序启动时boost::random::mt11213b播种的程序中全局使用RNG generator.seed(time(NULL));,因此这里有一个包装器单例RandomNumber

boost::random::uniform_int_distribution<unsigned long> 
    distribution(0, vec.size()-1);

for (unsigned long i=0;i<vec.size();i++)
    std::swap(vec[i], vec[distribution(RandomNumber::getInstance().generator)]);

简而言之,一些实验让我相信这个算法可能存在问题。这就是我所做的

  1. 创建了一个长度为 100 的整数向量
  2. 前 75 个元素填充0,后 25 个元素填充1
  3. 洗牌一个数组。
  4. 从列表中取出前 5 个元素并将它们相加。

我重复这个过程几千次(循环,而不是手动:))每次都从一个新的向量开始。然后我计算了总和的算术平均值,0.98而不是预期的1.25

1.22有趣的是,如果我从一个用相同算法而不是有序算法洗牌一次的向量开始,结果会增加结果大约1.25是预期值。

我不确定可能出了什么问题。该算法看起来不错,我能想到的唯一可能出错的是播种阶段和

boost::random::uniform_int_distribution<unsigned long> 
    distribution(0, vec.size()-1);

在洗牌向量之前每次调用的行(也许它应该只在程序中调用一次,但这没有意义)

任何帮助将不胜感激!

4

2 回答 2

3

如果我不得不猜测原因,那么您不会每次都在循环中更改分布大小。计算机编程算法的艺术就在这里

一旦你洗牌到 n 个元素,你就不想再碰第一个 n 了,因为重复应用伪随机数不会让事情变得更随机,它们会让它们变得不那么随机。

于 2012-04-23T19:25:14.427 回答
2

不,你的算法是错误的。考虑一个包含 4 个数字的向量的简单情况,您的算法会返回以下有偏差的结果

result      probability * 256
{1,2,3,4}   10
{1,2,4,3}   10
{1,3,2,4}   10
{1,3,4,2}   14
{1,4,2,3}   11
{1,4,3,2}   9
{2,1,3,4}   10
{2,1,4,3}   15
{2,3,1,4}   14
{2,3,4,1}   14
{2,4,1,3}   11
{2,4,3,1}   11
{3,1,2,4}   11
{3,1,4,2}   11
{3,2,1,4}   9
{3,2,4,1}   11
{3,4,1,2}   11
{3,4,2,1}   10
{4,1,2,3}   8
{4,1,3,2}   9
{4,2,1,3}   9
{4,2,3,1}   8
{4,3,1,2}   10
{4,3,2,1}   10

而标准的Fisher-Yates 算法将为所有结果提供统一的概率。

If you want to shuffle a vector, use std::random_shuffle directly (see Using boost::random as the RNG for std::random_shuffle for some example codes).

于 2012-04-23T19:32:23.153 回答