【问题标题】:C# Random does not work like a randomC# Random 不像随机数那样工作
【发布时间】:2012-07-24 00:36:13
【问题描述】:

我有一个图,每个节点有 4 个子节点。我编写了一个算法来生成从开始节点到结束节点的随机路径。在每个节点,它选择一个随机的下一个节点。访问过的节点可以重新访问。

代码如下:

public List<Node> GetPath(Node begin, Node end)
{
    var nodes = new List<Node>();
    var node = begin;
    while (node != end)
    {
        nodes.Add(node);
        var next = node.Children[new Random().Next(4)];
        node = next;
    }

    nodes.Add(end);

    return nodes;
}

但有时,Random 无法按预期工作。 “new Random().Next(4)”不断生成 0。因此它始终是第一个子节点被选中,并且生成了一个非常长的重复序列,如 node1->node2->node1->node2... 并最终生成发生内存不足异常。

有没有办法让 Random 类正常工作?

【问题讨论】:

标签: c# .net random


【解决方案1】:

原因是因为 Random 是根据当前时间初始化的(计算机中没有真正的随机......只有伪随机)。 while 循环迭代太快,并且系统时间没有记录更改。因此,您正在重新初始化一个以相同值开头的新 Random 对象。

尝试创建一个在整个方法中重复使用的 Random 对象:

public List<Node> GetPath(Node begin, Node end)
{
    var nodes = new List<Node>();
    var node = begin;

    Random r = new Random();
    while (node != end)
    {
        nodes.Add(node);
        var next = node.Children[r.Next(4)];
        node = next;
    }

    nodes.Add(end);

    return nodes;
}

【讨论】:

  • 谢谢。这确实解决了问题。但我遇到了另一个问题。实际上我在多线程中调用这个方法来生成一堆路径。如果在循环外使用 Random 。会生成很多相同的路径。我认为是因为在循环中使用 new Random 会产生很长的序列。
  • @Ryan:如果你在一个循环中多次调用它,你应该只为每个线程使用一个Random,最好基于来自全局共享Random的种子进行初始化(注意: Random 不是线程安全的,因此您需要锁定共享的 Random)。
【解决方案2】:

在循环外初始化随机实例,例如:

public List<Node> GetPath(Node begin, Node end)
{
    var nodes = new List<Node>();
    var node = begin;

    var random = new Random();

    while (node != end)
    {
        nodes.Add(node);
        var next = node.Children[random.Next(4)];
        node = next;
    }

    nodes.Add(end);

    return nodes;
}

【讨论】:

    【解决方案3】:

    您提到该方法在多个线程中被调用。一种解决方案是每个线程都有一个随机数生成器,由静态 rng 播种。

    我还删除了常量 4 并将其更改为 node.Children.Count

    static Random seed = new Random();
    [ThreadLocal] static Random rng;
    
    public List<Node> GetPath(Node begin, Node end)
    {
    var nodes = new List<Node>();
    var node = begin;
    
    if (rng == null)
       rng = new Random(seed.Next());
    
    while (node != end)
    {
        nodes.Add(node);
        var next = node.Children[rng.Next(node.Children.Count)];
        node = next;
    }
    
    nodes.Add(end);
    
    return nodes;
    }
    

    【讨论】:

      【解决方案4】:

      这里有几件事对你不利。第一个是每次你要求一个不同的数字,但这不是这个类所做的,也不是随机的定义。所以,这个类实际上工作正常。

      随机的定义

      1. 在没有方法或有意识的决定的情况下做出、完成、发生或选择:“100 个家庭的随机样本”。
      2. 由或涉及每个项目的平等机会。

      现在,这个班级尽最大努力为每个选项提供平等的选择机会。因此,当您想到随机时,请确保您将术语的定义置于上下文中。但是,请记住,这个类并不像人脑那样工作。

      现在,为了解决您经常变为零的事实,它的发生有两个原因。首先,您在每次迭代中创建一个new Random 类。但更重要的是,你的范围太小了,因为你希望它每次在只有 4 个选项的范围内给你一个不同的数字,而且因为它是伪随机的,就像MSDN 说你得到相同的答案经常。

      我知道您只给它 4 个选项的原因,但我认为您可能需要重新考虑您正在寻找的功能类型,因为它可能会减少挫败感。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-04-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多