随机数组生成,没有重复

我正在尝试创建一些生成随机数组但没有重复值的内容。 我已经看过其他答案,但似乎没有人帮我理解。 我想不出实际生成不包含重复项的随机数的方法。 这是我到目前为止所尝试的:

srand(time(NULL)); int numbers [4]; for (int x=0; x!=4;x++) { numbers[x] = 1 + (rand() % 4) ; printf("%d ", numbers[x]); } 

任何帮助将不胜感激。

首先, rand()是一个随机数,但不是重复的。

如果要生成一个没有重复的随机数组rand()方法根本不起作用。

假设您要生成一个包含1000个数字的数组。 在最好的情况下,假设您生成了没有重复的前999个数字,并且最后认为要生成 最后一个数字获得该数字的概率是1/1000,因此这几乎需要永远生成。 实际上只有10个数字会造成很大麻烦。

最好的方法是通过增量( 或严格的单调序列 )生成所有数字。 在这种情况下,不会有重复

以下是如何使用10个数字进行操作的示例。 即使有1000个数字,它也能正常工作 。

注: Jhon Leehey 回答的 Sufflefunction。

 #include  #include  #include  void shuffle(int *arr, size_t n) { if (n > 1) { size_t i; srand(time(NULL)); for (i = 0; i < n - 1; i++) { size_t j = i + rand() / (RAND_MAX / (n - i) + 1); int t = arr[j]; arr[j] = arr[i]; arr[i] = t; } } } int main() { int i; int arr[10]; for (i=0; i<10; i++){ arr[i] = i; } shuffle(arr, 10); for (i=0; i<10; i++){ printf("%d ", arr[i]); } } 

您开始填充具有从0开始的连续元素的容器

std::iota(begin(vec), end(vec), 0);

然后你给自己一个像样的随机数生成器并正确播种

std::mt19937 rng(std::random_device{}());

最后你用rng来洗牌

std::shuffle(begin(vec), end(vec), rng);

住在coliru


在某些实现中, random_device无法正常工作(最明显的是在Windows上使用gcc),您必须使用替代种子,即当前时间→ chrono

有2种解决方案可供选择:

  1. 使用rand()之类的东西生成随机数并检查重复项。

  2. 找到严格单调(最好是严格增加)的数学序列,并将其术语作为数组的成员。 然后,您可以随机播放arrays。 结果不是真正随机的,但是使用rand()都不会。 rand()使用了一个simillar tehnique,这就是为什么我们需要设置一些改变的种子,就像时间一样。 例如,您可以使用时间来生成序列的第一个元素,并且使用良好的序列,您的结果至少是合适的。 请注意,序列必须严格单调,以避免产生重复。 序列不必太复杂。 例如,如果您将unix time modulo 10000作为第一个术语,然后使用像x [i] = x [i-1] + 3 * x [i-2]这样的reccure生成其他术语应​​该没问题。 当然,您也可以使用更复杂的序列,但在溢出时要小心(因为您不能对结果应用模运算符,因为它不会再增加)和您想要的数字位数。

 srand(time(NULL)); const int N = 4; int numbers [N]; bool isAlreadyAdded(int value, int index) { for( int i = 0; i < index; i ++) if( numbers[i] == value) return true; return false; } for (int x=0; x!=N;x++) { int tmp = 1 + (rand() % N) ; while( x !=0 && isAlreadyAdded(tmp, x)) tmp = 1 + (rand() % N) ; numbers[x] = tmp; printf("%d ", numbers[x]); } 

这只是一种方式。 它应该工作,当然有更好的方法

在c ++中,您只需要:

 std::random_shuffle() 

http://www.cplusplus.com/reference/algorithm/random_shuffle/

 int numbers [4]; for (int x=0; x!=4;x++) { numbers[x] = x; } std::random_shuffle(numbers, numbers +4); 

更新 :好的,我一直在想一个合适的地图function可以从每个索引到一个随机数,但是再想一想我意识到这可能很难。 以下应该有效:

  int size = 10; int range = 100; std::set sample; while(sample.size() != size) sample.insert(rand() % range); // Or whatever random source. std::vector result(sample.begin(), sample.end()); std::random_shuffle ( result.begin(), result.end() ); 

您可以使用自己的随机数生成器,其序列大于或等于数组的长度。 有关说明,请参阅http://en.wikipedia.org/wiki/Linear_congruential_generator#Period_length 。

所以你需要LCG,表达式为Xn + 1 =(aXn + c)mod m。 值m必须至少与数组的长度一样大。 检查“是否且仅当”最大序列长度的条件,并确保您的数字满足它们。

因此,对于大多数用途,您将能够生成具有令人满意的随机性的随机数,这保证在前m次调用中不会重复任何数字。

生成每个随机数后,循环显示先前的值并进行比较。 如果匹配,请重新生成新值并重试。

这个怎么样:

 #define NUMS (10) int randomSequence[NUMS] = {0}, i = 0, randomNum; bool numExists[NUMS] = {false}; while(i != NUMS) { randomNum = rand() % NUMS; if(numExists[randomNum] == false) { randomSequence[i++] = randomNum; numExists[randomNum] = true; } } 

当然, NUMS越大,执行while循环所需的时间越长。

如果你想在不保持访问索引的情况下伪随机遍历大空间,你应该看看我多年前为基本技术做出的贡献。 http://packetfactory.openwall.net/projects/ipspace/index.html

您应该能够根据自己的需要调整它,源位于页面底部。