2010-12-03 28 views
4

我有很多随机列表的问题。我在谈论一个200个元素的列表,我想在这里列出这些列表。不要误会我的意思,我读了很多的例子,乍看之下有相当不错的事情,就像这样:C#随机代码 - 大部分都是错误的吗?

Randomize a List<T>

但以我的经验,至少有一个快速的机器上,这是基本不值钱。混洗工作如此之快,以至于在两次调用Random.NEXT()之间没有MS延迟,这导致了几乎不随机的行为。

我不是在谈论超安全的东西,只是一个基本的游戏随机。我知道我可以添加1个MS的延迟,但这意味着“浪费”200个MS只是为了随机化一个列表。

现在我发现这种方法:http://www.codinghorror.com/blog/2007/12/shuffling.html

它看起来不错,使用GUID来排序。但是他们是不是以同样的方式创造出来的?让我们一步了一个缺口,让我们假设我要创建1000个数字,从0 - 5此代码是基本没用:

 var resultA = new List<int>(); 
     for (int i = 0; i < 1000; i++) 
     { 
      resultA.Add(new Random().Next(5)); 
     } 


     var resultB = new List<int>(); 
     for (int i = 0; i < 1000; i++) 
     { 
      resultB.Add(new Random().Next(5)); 
      Thread.Sleep(1); 
     } 

A不会在所有的工作,至少在Windows手机没有我的即时通讯环境7. B很好,但需要一秒钟,这也是愚蠢的。任何意见或想法,它不可能很难创建一个随机的整数列表:-)

+0

哦,我真的很讨厌自己现在:-)好吧,这解释了它..那么有一些问题,它是有道理的,用一个新的随机(每题被创造,它应该放置项目在1-4,所以这个问题照顾整个事情),但他们被创建的速度..好吧,谢谢,我的愚蠢的错误! – 2010-12-03 17:17:43

+0

在你引用的问题上使用shuffle扩展 - 或者看看你能不能找到Jon Skeet的实现,这是另一回事。在同一个RNG上对Next()的连续调用通常应该返回不同的值(尽管它是“随机的”,所以你可能会周期性地重复)。 – tvanfosson 2010-12-03 17:19:10

+0

是的,有了这些问题,我只是将随机生成器移动到父对象(游戏),所以没有问题了。但是,有趣的是,你可以多久寻找这个愚蠢的错误,而且我确定“随机数”不会那么难。应该早些时候问过:-) – 2010-12-03 17:22:47

回答

22

不要继续初始化一个新的实例Random;只做一个并不断引用它。

var random = new Random(); 
var resultA = new List<int>(); 
for (int i = 0; i < 1000; i++) 
{ 
    resultA.Add(random.Next(5)); 
} 

你是正确的,同样的“时间戳”内反复营造的Random新实例将导致相同的种子;但在随机“前进”实例上调用.Next种子,以便您检索的下一个数字(最有可能)不同。

这也包括在the documentation on Random

...因为时钟具有有限的分辨率,使用参数的构造函数来创建紧密相继不同的随机对象的创建产生随机数的相同序列的随机数发生器。

...

这个问题可以通过创建一个单一的随机对象,而不是多个被避免。

6

您需要保持Random的相同实例。

var random = new Random(); 

    var resultA = new List<int>(); 
    for (int i = 0; i < 1000; i++) 
    { 
     resultA.Add(random.Next(5)); 
    } 


    var resultB = new List<int>(); 
    for (int i = 0; i < 1000; i++) 
    { 
     resultB.Add(random.Next(5)); 
     Thread.Sleep(1); 
    } 

这是因为当随机初始化它使用系统时钟来获得一个时间点。当你下一次通话时,它可以使用时间差来获得下一个号码。如果你持续初始化一个Random对象,大部分时间你都会得到相同的数字。

4

混洗工作如此之快,以致两次调用Random.NEXT()之间没有MS延迟,从而导致几乎不随机的行为。

是什么让你觉得两个电话之间需要ms延迟Random.Next

您的沼泽标准随机数生成器将采取一些初始种子(比如说系统时钟),然后重复一些算法来生成一个看似随机的数字序列。这些算法中的大多数不会将时钟作为种子以外的输入,因此,执行两次连续调用的速度并不重要。

您的代码失败的原因是因为您在每次迭代时都要实例化一个新的随机数生成器。这是时钟可以杀死你的地方,因为你最终会得到两次相同的种子。 您不会在同一随机数发生器上连续呼叫Random.Next。您在每次迭代时都要在一个新的随机数生成器上调用Random.Next,并且有时候这些随机数生成器会使用相同的值播种,因为您使用系统时钟播种它们。

移动循环之外的随机数生成器的实例化。

var resultA = new List<int>(); 
Random rg = new Random(); 
for (int i = 0; i < 1000; i++) { 
    resultA.Add(rg.Next(5)); 
}