在使每个索引具有与任何索引相同的概率的同时对数组进行混洗

时间:2018-01-04 18:17:10

标签: c algorithm random shuffle

我想改组一个数组,并且每个索引都有与其他索引相同的概率(不包括它自己)。

我有这个解决方案,只有我发现总是最后两个索引总是相互交换:

void Shuffle(int arr[]. size_t n)
{
  int newIndx = 0;
  int i = 0;

  for(; i > n - 2; ++i)
  {
    newIndx = rand() % (n - 1);
    if (newIndx >= i)
    {
      ++newIndx;
    }

    swap(i, newIndx, arr);
  }
}

但最终可能是某些索引会再次回到原来的位置。

有什么想法吗?

C lang。

1 个答案:

答案 0 :(得分:0)

您的算法只有几乎正确(在算法中意味着意外的结果)。由于散布的一些小错误,它不会产生预期的结果。

首先,rand() % N不能保证产生均匀分布,除非N是可能值数的除数。在任何其他情况下,你会有轻微的偏见。无论如何,我rand的手册页将其描述为错误的随机数生成器,因此您应该尝试使用randomarc4random_uniform

但是避免索引回到原来的位置既是一致的,也很难实现。我能想象的唯一方法是保留一个数字数组[0; n [和交换它与真实数组相同,以便能够知道数字的原始索引。

代码可能变成:

void Shuffle(int arr[]. size_t n)
{
  int i, newIndx;
  int *indexes = malloc(n * sizeof(int));
  for (i=0; i<n; i++) indexes[i] = i;
  for(i=0; i < n - 1; ++i)           // beware to the inequality!
  {
    int i1;
    // search if index i is in the [i; n[ current array:
    for (i1=i; i1 < n; ++i) {
      if (indexes[i1] == i) {          // move it to i position
        if (i1 != i) {                 // nothing to do if already at i
          swap(i, i1, arr);
          swap(i, i1, indexes);
        }
        break;
      }
    }
    i1 = (i1 == n) ? i : i+1;          // we will start the search at i1
                                       // to guarantee that no element keep its place
    newIndx = i1 + arc4random_uniform(n - i1);
    /* if arc4random is not available:
    newIndx = i1 + (random() % (n - i1));
    */
    swap(i, newIndx, arr);
    swap(i, newIndx, indexes);
  }
  /* special case: a permutation of [0: n-1[ have left last element in place
   * we will exchange the last element with a random one
   */
  if (indexes[n-1] == n-1) {
    newIndx = arc4random_uniform(n-1)
    swap(n-1, newIndx, arr);
    swap(n-1, newIndx, indexes);
  }
  free(indexes);    // don't forget to free what we have malloc'ed...
}

注意:算法应该是正确的,但代码尚未经过测试,可能包含错别字......