【问题标题】:Arraylist Shuffle algorithm using a key使用密钥的 Arraylist Shuffle 算法
【发布时间】:2015-01-17 18:42:45
【问题描述】:

如何在 C# ArrayList 中编写一个可逆的随机播放算法,该算法使用一个密钥进行随机播放并且可以反转到原始状态?

【问题讨论】:

  • 与其担心能否逆转它,存储原始状态的副本似乎要简单得多。
  • Matt 已经说过复制的替代建议:创建第二个数组来存储索引 0、...、n。将其初始化为其他数组 (n) 的长度,然后对索引数组进行洗牌。当你想以随机顺序访问第一个数组时,只需使用 shuffled 索引数组来查找原始条目。

标签: c# arraylist shuffle


【解决方案1】:
    private class myItem
    {
        public Int32 ID { get; set; }
        public Int32 Rand { get; set; }
        public String Value { get; set; }

    }

    private void Main(object sender, EventArgs e)
    {

        string[] array = new string[] { "alpha", "beta", "gamma", "delta" };
        List<myItem> myArray = addKeys(array);//adds keys to array required for randomization and reversing
        string[] randomarray = randomize(myArray);
        string[] reversedarray = reverse(myArray);

    }
    private List<myItem> addKeys(string[] array)
    {
        Random random = new Random();
        List<myItem> myArr = new List<myItem>();
        for (int i = 0; i < array.Length; i++)
        {
            myArr.Add(new myItem { ID = i, Rand = random.Next(), Value = array[i] });

        }
        return myArr;
    }
    private string[] randomize(List<myItem> myArray)
    {
        return (from item in myArray
                         orderby item.Rand
                         select item.Value).ToArray();
    }
    private string[] reverse(List<myItem> myArray)
    {
        return (from item in myArray
                         orderby item.ID
                         select item.Value).ToArray();
    }

【讨论】:

    【解决方案2】:

    您可以使用 KeyValuePair。您可以在以下站点获得详细说明:http://www.dotnetperls.com/shuffle

    但是,如果您想反转它,我建议使用 DataTable。在第一列中,您可以拥有原始排序顺序(可能是整数),在第二列中,您可以创建随机数。在第三列中,您可以拥有需要排序的值。然后使用按第二列的排序来洗牌,然后按第一列排序来恢复它。

    【讨论】:

      【解决方案3】:

      Shuffling一个数组是通过多次交换数组内的元素来完成的。

      如果您获取一个数组,则交换元素,然后再次交换它们,但是按照最初交换它们的相反顺序,您将得到原始数组。

      这些改组位置可以从PRNG (Pseudorandom number generator) 生成。对于给定的seedPNRG 将始终生成相同的数字:这将是您的“关键”。

      这是一些使用该想法的代码(Fisher Yates 用于随机播放):

      public static void Shuffle(ArrayList list, int seed, bool reverse = false)  
      {           
          Random rng = new Random(seed); 
          List<Tuple<int, int>> swaps = new List<Tuple<int, int>>();
          int n = list.Count;  
      
          //prepare swapping positions 
          while (n > 1) {  
              n--;  
              int k = rng.Next(n + 1);  
              swaps.Add(new Tuple<int, int>(k, n));
          }
      
          //reverse if needed
          if(reverse)
              swaps.Reverse();
      
          //swap the items
          foreach(Tuple<int, int> swap in swaps)
          {       
              object value = list[swap.Item1];  
              list[swap.Item1] = list[swap.Item2];  
              list[swap.Item2] = value;
          }
      }
      

      用法:

      ArrayList a = new ArrayList();
      int key = 2742;
      
      Shuffle(a, key);
      Shuffle(a, key, true);
      

      请注意,如果您不希望键是整数,而是字符串,则可以使用完全相同的方法,但整数使用 "somekey".GetHashCode()

      【讨论】:

        【解决方案4】:

        这是一种简单的方法,只需要您存储“密钥”,并且不更改洗牌算法。

        只要您可以重现它,您使用哪种 shuffle 算法并不重要,这意味着如果您使用相同的密钥或种子,并运行两次 shuffle 算法,两次都会以完全相同的方式进行 shuffle。

        如果您能做到这一点,使用密钥或随机播放算法的种子,那么您就可以开始了。

        为了扭转它,你所要做的就是打乱一个整数数组,其中在打乱之前数组中的值对应于每个元素的索引。改组后,使用与上述相同的键或种子,您现在有了一个改组副本,其中每个值都是未改组数组中原始位置的索引。

        让我举个例子。

        假设一个包含 4 个整数的数组,值从 0 到 3(索引为 0 的元素的值为 0,索引为 1 的元素的值为 1,依此类推)。

        打乱这个,得到这个数组:3, 1, 2, 0。

        这意味着洗牌数组的第一个元素曾经位于索引 3,第二个元素位于索引 1,第三个位于索引 2,第四个位于索引 0。

        【讨论】:

        • 思路不错,但描述不正确。您已经说过要求是(相同的输入,相同的键)给出(相同的随机顺序),但然后您将其应用于(不同的输入,相同的键)。在那种情况下,(相同的洗牌顺序)是不确定的。我认为你需要加强你的条件。
        • 我会改写,“输入”是指键或种子,而不是被洗牌的元素。
        猜你喜欢
        • 1970-01-01
        • 2016-08-12
        • 2011-04-02
        • 1970-01-01
        • 2016-03-12
        • 2015-08-30
        • 2013-02-13
        • 2023-04-02
        • 2011-03-20
        相关资源
        最近更新 更多