无重复的随机数组生成
Random array generation with no duplicates
我正在尝试创建一个生成没有重复值的随机数组的东西。我已经看了其他答案,但似乎没有一个能帮助我理解。我想不出一种方法来真正生成不包含重复的随机数。以下是我迄今为止所尝试的:
srand(time(NULL));
int numbers [4];
for (int x=0; x!=4;x++)
{
numbers[x] = 1 + (rand() % 4) ;
printf("%d ", numbers[x]);
}
您开始用从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
。
首先,rand()
生成随机数,但不包含重复数。
如果要生成不重复的随机数组,则rand()
方法根本不起作用。
假设您想生成一个1000个数字的数组。在最好的情况下,假设您生成了前999个没有重复的数字,最后一个想法是生成最后一个数字得到这个数字的概率是1/1000所以生成这个数字几乎需要很长时间。在实践中,只有10个数字会带来很大的麻烦。
最好的方法是通过递增(或严格单调序列)生成所有数字,对它们进行洗牌。在这种情况下,将有无重复
下面是一个如何使用10个数字的例子。即使有1000个数字,它也在起作用。
注:从Jhon Leehey的回答来看,函数足够了。
#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]);
}
}
有两种解决方案可供选择:
-
使用rand()之类的东西生成随机数并检查重复项。
-
找到一个严格单调(最好是严格递增)的数学序列,并将其项作为数组的成员。然后,您可以洗牌。结果不会是真正随机的,但使用rand()也不会。rand()使用了类似的tehnique,这就是为什么我们需要用一些变化的东西来设定种子,比如时间。例如,您可以使用时间来生成序列的第一个元素,使用一个好的序列,您的结果至少会不错。请注意,序列必须是严格单调的,以避免产生重复。顺序不必太复杂。例如,如果您将unix时间模10000作为第一个项,然后使用类似x[i]=x[i-1]+3*x[i-2]的递归生成其他项,应该是可以的。当然,你也可以使用更复杂的序列,但要小心溢出(因为你不能对结果应用模运算符,因为它不会再增加了)和你想要的位数。
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]);
}
这只是一种方式。它应该起作用,当然还有更好的方法
这个怎么样:
#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
循环所需的时间就越长。
在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() );
您可以使用自己的随机数生成器,该生成器的序列大于或等于数组的长度。提到http://en.wikipedia.org/wiki/Linear_congruential_generator#Period_length以获取说明。
所以您需要表达式Xn+1=(aXn+c)mod m的LCG。值m必须至少和数组的长度一样大。检查最大序列长度的"如果且仅当"条件,并确保您的数字满足这些条件。
因此,您将能够为大多数用途生成具有令人满意随机性的随机数,这保证了在前m个调用中不会重复任何数字。
生成每个随机数后,循环使用前面的值并进行比较。如果匹配,请重新生成一个新值,然后重试。
如果你想在不维护访问索引的情况下伪随机遍历大空间,你应该看看我几年前参与的这个项目,了解基本技术。http://packetfactory.openwall.net/projects/ipspace/index.html
您应该能够根据自己的目的对其进行调整,源代码位于页面底部。
- 在将数字随机生成为数组期间从内存输出随机数的数组
- 将随机生成的数字添加到数组 + 对这些数组求平均值
- C++具有随机计数的数组
- 从C++数组中选择一个随机元素
- 为什么我的 2d 数组的第二行从 RAM 中获取随机值?
- 该程序将.csv文件中的一系列单词放入数组中,然后随机生成句子.但它不起作用
- 为什么我的数组值会更新为随机值?
- 在 c++ 的 10x10 数组中生成特定数量的多个随机字符
- SFINAE - 检测类型 T 是指针、数组还是带有随机访问运算符的容器,以及给定的值类型
- 动态数组传递给 main 中用随机值填充的函数,返回值3221226356
- 选择随机字符串数组的排序
- 如何在 3x4 数组中随机 4 个不同的位置
- 字符数组中的十六进制导致写入套接字时出现随机字符
- 更快地访问 C++ 数组中的随机元素
- 通过数组C 随机增加
- C++ 数组随机播放不起作用
- 将多维数组随机化(随机播放)为另一个 2D 数组
- 使用二维数组随机生成器objective c和c++
- 数组随机存取c++
- 多维数组随机漫步程序