【问题标题】:Random slot algorithm随机槽算法
【发布时间】:2026-01-02 11:50:01
【问题描述】:

我有二维数组。我想随机选择一个插槽,并继续这样做,直到我最终选择了所有插槽(所以当然最后一次选择没有随机性)之前不要两次选择同一个插槽。是否有一个众所周知的算法来做到这一点?我正在使用 C#,但显然这更多的是关于算法而不是任何特定平台。是的,“大书”在我的购买清单上 :)

【问题讨论】:

标签: c# .net random


【解决方案1】:

看看 Fisher-Yates shuffle。它旨在从集合中选择随机排列。

【讨论】:

    【解决方案2】:

    使用前面提到的Fisher-Yates shuffle 算法(在 O(n) 时间内)

    int X = 3;  int Y = 4;
    int[] array = new int[X * Y];
    
    for (int i = 0; i < array.Length; i++) array[i] = i;
    FisherYatesShuffle(array);
    
    var randomSlots = array.Select((i,j) => new {x=array[j]%X , y=array[j]/X })
                           .ToArray();
    

    public static void FisherYatesShuffle<T>(T[] array)
    {
        Random r = new Random();
        for (int i = array.Length - 1; i > 0; i--)
        {
            int j = r.Next(0, i + 1);
            T temp = array[j];
            array[j] = array[i];
            array[i] = temp;
        }
    }
    

    【讨论】:

      【解决方案3】:

      假设你的数组是这样的:

      Random rand = new Random();
      
      object[,] array = new object[width,height];
      bool[,] chosen = new bool[width,height];
      
      int i, j;
      do
      {
          i = rand.Next(width);
          j = rand.Next(height);
      } while (chosen[i,j]);
      
      chosen[i,j] = true;
      object current = array[i,j];
      

      这应该可以正常工作。

      【讨论】:

      • 谢谢,比上面的递归解决方案更好,但是当我们接近集合的末尾时,我们仍然会越来越多地循环。也许这只是一个不可避免的问题?
      • @MylesMcDonnell 我认为这是无法避免的,您的编辑破坏了代码的功能。它不应该是!,如果选择设置为 true,则该索引无效。我已经回滚了代码。
      • 抱歉弄乱了你的答案;)
      • @RichardJ.RossIII 道歉..@Fuex 我认为我们都犯了同样的错误
      【解决方案4】:

      我这样做是为了数字

      list<int> PastList=new PastList<int>();
      private void Choоse()
      {
         int i = Recurs();
         PastList.Add(i);
      }
      
      private int Recurs()
      {
         int i;
      
         i = rnd.Next(0, 99);
         if (PastList.Contains(i))
         {
             i = Recurs();
         }
      
         return i;
      }
      

      【讨论】:

      • 这个问题是我们越接近集合的末尾,就会发生更多的递归。可能需要多次调用 rnd.Next(0,99) 才能获得最后一项。哎哟。