我在C中编写了这个函数,我想让它创建一个随机排列或从1到n的数字列表。我无法让它没有重复的数字。所以,如果你有n = 4,我希望它只返回一个包含1-4的随机数组,例如:{1,3,4,2}
int* random(int n)
{
int* r = malloc(n * sizeof(int));
// initial range of numbers
for(int i=0;i<n;++i){
r[i]=i+1;
}
// shuffle
for (int i = 1; i <= n; ++i){
int j = rand() % i;
r[i] = r[j];
r[j] = i;
}
return r;
}
答案 0 :(得分:10)
将您的第二个for
循环更改为:
for (int i = n-1; i >= 0; --i){
//generate a random number [0, n-1]
int j = rand() % (i+1);
//swap the last element with element at random index
int temp = r[i];
r[i] = r[j];
r[j] = temp;
}
这是Fisher-Yates改组算法。我听说使用rand() % n
没有统一分发,你已经被警告了。
如果您希望每次都生成唯一的排列,您可以将生成的排列存储在Dictionary
或Hashmap
中,然后在每次返回时进行查找。我不认为C
内置了一个,但应该有可用的库。
答案 1 :(得分:0)
它可能不是最有效的方法,但由于你已经在开始时填充数组,你可以只循环遍历元素,并为每个元素选择1到n范围内的随机索引,并与该项交换:
int* random(int n)
{
int* r = malloc(n * sizeof(int));
for(int i=0;i<n;++i){
r[i]=i+1;
}
for(int i=0; i<n; ++i){
int randIdx = rand() % n;
// swap r[i] with r[randIdx]
int t = r[i];
r[i] = r[randIdx];
r[randIdx] = t;
}
return r;
}
我不知道这是否是最有效的,或者即使它给出了最好的分布。但这很简单: - )
答案 2 :(得分:0)
如果你想多次重复以上,又不想每次都得到相同的排列,只需在开头添加以下行:
srand((unsigned)time(NULL));