随机数组生成,没有重复

时间:2013-12-22 22:35:31

标签: c++ c random

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

srand(time(NULL));
int numbers [4];

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

任何帮助将不胜感激。

9 个答案:

答案 0 :(得分:16)

您开始使用从0

开始的连续元素填充容器

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

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

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

最后你使用rng

来改变元素

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

live on coliru


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

答案 1 :(得分:6)

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

如果要生成随机数组没有重复项rand()方法根本无效。

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

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

Here是关于如何使用10个数字的例子。即使有1000个数字,它也是working

注意:来自Jhon Leeheyanswer的补课功能。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

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]);
    }
}

答案 2 :(得分:2)

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

  1. 使用rand()等内容生成随机数并检查重复项。

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

答案 3 :(得分:1)

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]);
}

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

答案 4 :(得分:0)

在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);

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

    int size = 10;
    int range = 100;

    std::set<int> sample;

    while(sample.size() != size)
        sample.insert(rand() % range); // Or whatever random source.

    std::vector<int> result(sample.begin(), sample.end());

    std::random_shuffle ( result.begin(), result.end() );

答案 5 :(得分:0)

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

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

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

这个怎么样:

#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循环所需的时间就越长。

答案 8 :(得分:0)

如果你想伪随机遍历大空间而不维护访问索引,你应该看看我多年前为基本技术做出贡献的这个项目。 http://packetfactory.openwall.net/projects/ipspace/index.html

您应该能够根据自己的目的进行调整,来源位于页面底部。