我正在使用此代码使用Fisher-Yates随机化算法的变体生成向量的随机置换(我从第一个元素到最后一个元素,而不是相反)。我在程序启动时在boost::random::mt11213b
播种的程序中全局使用generator.seed(time(NULL));
RNG,因此这里是一个包装单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)]);
一些实验让我相信这个算法可能存在一个问题,简而言之。这就是我所做的
0
填充前75个元素,使用1
我重复这个过程几千次(用一个循环,而不是手工操作:))每次都以一个新的向量开始。然后我计算了总和的算术平均值,它来自0.98
而不是预期的1.25
。
有趣的是,如果我从一个使用相同算法而不是有序算法一次洗牌的向量开始,结果会增加到1.22
并且如果我不在每次迭代时丢弃该向量但只是将其再次洗牌,结果大约为1.25
,即期望值。
我不确定可能出现的问题。该算法看起来很合理,我能想到的唯一可能出错的是播种阶段和
boost::random::uniform_int_distribution<unsigned long>
distribution(0, vec.size()-1);
每次在向量被洗牌之前被调用的行(也许它应该只在一个程序中被调用但是不会有意义)
任何帮助将不胜感激!
答案 0 :(得分:3)
如果我不得不猜测原因,那么每次循环时你都不会改变分布大小。 计算机编程艺术算法是here。
一旦你改组为n个元素,你不想再次触及前n个,因为伪随机数的重复应用不会使事情更随机,它们会使它们随机性降低。
答案 1 :(得分: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 algorithm将为所有结果提供统一的概率。
如果您想要随机播放一个向量,请直接使用std::random_shuffle
(有关示例代码,请参阅Using boost::random as the RNG for std::random_shuffle)。