C语言中的洗牌数组
我正在寻找一个ANSIC中的函数,它可以像PHP的C语言中的洗牌数组,c,arrays,C,Arrays,我正在寻找一个ANSIC中的函数,它可以像PHP的shuffle()一样随机化数组。有这样一个函数吗?还是我必须自己写?如果我必须自己写,那么最好/最有效的方法是什么 到目前为止,我的想法是: 例如,在数组中迭代100次,并将一个随机索引与另一个随机索引交换 创建一个新数组,并使用第一个数组中的随机索引填充该数组,每次检查是否已获取索引(性能=0复杂性=严重) 在C标准中没有随机化数组的函数 看看Knuth,他有这项工作的算法 或者看看宾利-编程珍珠或更多编程珍珠 或者看看几乎所有的算法书
shuffle()
一样随机化数组。有这样一个函数吗?还是我必须自己写?如果我必须自己写,那么最好/最有效的方法是什么
到目前为止,我的想法是:
- 例如,在数组中迭代100次,并将一个随机索引与另一个随机索引交换
- 创建一个新数组,并使用第一个数组中的随机索引填充该数组,每次检查是否已获取索引(性能=0复杂性=严重)
- 看看Knuth,他有这项工作的算法
- 或者看看宾利-编程珍珠或更多编程珍珠
- 或者看看几乎所有的算法书
#include <stdlib.h>
/* Arrange the N elements of ARRAY in random order.
Only effective if N is much smaller than RAND_MAX;
if this may not be the case, use a better random
number generator. */
void shuffle(int *array, size_t n)
{
if (n > 1)
{
size_t i;
for (i = 0; i < n - 1; i++)
{
size_t j = i + rand() / (RAND_MAX / (n - i) + 1);
int t = array[j];
array[j] = array[i];
array[i] = t;
}
}
}
这里有一个使用memcpy而不是赋值的解决方案,所以您可以将它用于任意数据上的数组。您需要两倍于原始阵列的内存,成本为线性O(n):
void main()
{
int elesize=sizeof(int);
int i;
INTR;
int src[20];
int-tgt[20];
对于(i=0;i<20;src[i]=i++);
srand((无符号整数)时间(0));
对于(i=20;i>0;i--)
{
r=rand()%i;
memcpy(&tgt[20-i],&src[r],elesize);
memcpy(&src[r],&src[i-1],elesize);
}
对于(i=0;i<20;printf(“%d”,tgt[i++]);
}
我将附和尼尔·巴特沃斯的答案,并指出你第一个想法的一些问题:
你建议,
例如,在数组中迭代100次,并将一个随机索引与另一个随机索引交换
让这更严格。我将假设存在randn(int n)
,一个围绕某个RNG的包装器,生成均匀分布在[0,n-1]中的数字,交换(int a[],size\u ti,size\u t j)
它交换a[i]
和a[j]
。
现在让我们实施你的建议:
void silly_shuffle(size_t n, int a[n]) {
for (size_t i = 0; i < n; i++)
swap(a, randn(n), randn(n)); // swap two random elements
}
ETA:另请参见。以下代码确保数组将根据从usec时间中获取的随机种子进行洗牌。这也正确地实现了。我已经测试了这个函数的输出,它看起来不错(甚至期望任何数组元素都是洗牌后的第一个元素,也期望是最后一个)
我没有在答案中看到这一点,因此我提出了这个解决方案,如果它能帮助任何人:
static inline void shuffle(size_t n, int arr[])
{
size_t rng;
size_t i;
int tmp[n];
int tmp2[n];
memcpy(tmp, arr, sizeof(int) * n);
bzero(tmp2, sizeof(int) * n);
srand(time(NULL));
i = 0;
while (i < n)
{
rng = rand() % (n - i);
while (tmp2[rng] == 1)
++rng;
tmp2[rng] = 1;
arr[i] = tmp[rng];
++i;
}
}
static inline void shuffle(大小\u t n,整数arr[])
{
尺寸;
尺寸i;
int-tmp[n];
int-tmp2[n];
memcpy(tmp、arr、sizeof(int)*n);
bzero(tmp2,sizeof(int)*n);
srand(时间(空));
i=0;
而(i
您要查找的函数已存在于标准C库中。它的名字是qsort
。随机排序可以实现为:
int rand\u比较(常数void*a,常数void*b)
{
(a)无效;(b)无效;
返回rand()%2?+1:-1;
}
空洗牌(空*基、大小\u t NMMB、大小\u t大小)
{
qsort(基数、nmemb、大小、rand_比较);
}
例如:
intarr[10]={0,1,2,3,4,5,6,7,8,9};
srand(0);/*每个排列在这里都有编号*/
洗牌(arr,10,sizeof(int));
…输出为:
3, 4, 1, 0, 2, 7, 6, 9, 8, 5
答案与Nomadiq相同,但随机性保持简单。 如果您一个接一个地调用函数,则随机数将相同:
#include <stdlib.h>
#include <time.h>
void shuffle(int aArray[], int cnt){
int temp, randomNumber;
time_t t;
srand((unsigned)time(&t));
for (int i=cnt-1; i>0; i--) {
temp = aArray[i];
randomNumber = (rand() % (i+1));
aArray[i] = aArray[randomNumber];
aArray[randomNumber] = temp;
}
}
#包括
#包括
无效洗牌(int aArray[],int cnt){
int-temp,随机数;
时间;
srand((未签名)时间(&t));
对于(int i=cnt-1;i>0;i--){
温度=aArray[i];
随机数=(rand()%(i+1));
aArray[i]=aArray[randomNumber];
aArray[随机数]=温度;
}
}
你必须自己写——这很简单。看见和往常一样,在处理随机数时,想出自己的解决方案通常是个坏主意,好吧,别管它了,Find it>>注意维基百科页面上确定的“模偏差”——Ben-Pfaff算法显示了这个问题。另请参见这篇文章,它展示了如何洗牌,以及如何不洗牌:,代码应该可以轻松地传输到CIn,为了避免在每次迭代中分配t,您应该交换两个不带临时变量的整数:array[i]^=array[j];数组[j]^=数组[i];数组[i]^=数组[j];你也可以做array[i]+=array[j];数组[j]=数组[i]-数组[j];数组[i]-=数组[j]代码>如果您不担心int溢出。“我不想把XOR'ing的工作原理与语言中的任何新成员混淆…@Hyperboreus-你在开玩笑吗?”?在堆栈上“分配”整数就像在寄存器上执行加法/减法一样简单。这本身就足够快了,但更进一步说,一个好的优化器只会对这段代码做一次加法/减法运算,而不是每次迭代。(在打开优化的情况下编译此文件,并亲自查看反汇编。我使用gcc-S
进行了反汇编,堆栈指针有两次修改,一次在函数的开头,一次在函数的结尾。)如果在函数前面设置了t
和j
的作用域,则不会保存任何内容。注意:公式i+r/(RAND_MAX/(n-i)+1)
引入了额外的偏差。e、 g.j(i=32,n=61,RM=2147483647)-->{2147483648个不同的r
,j
=32到60出现74051161个,61只出现74051140}。待定最坏情况i,n,RAND\u MAX
。当i+rnd%(n-i)
{j
=32到39分别出现74051161时,j
=40到61出现74051160,最坏情况分布
void bad_shuffle(size_t n, int a[n]) {
for (size_t i = 0; i < n; i++)
swap(a, i, randn(n));
}
void fisher_yates_shuffle(size_t n, int a[n]) {
for (size_t i = 0; i < n; i++)
swap(a, i, i+randn(n-1-i)); // swap element with random later element
}
void shuffle(int *array, size_t n) {
struct timeval tv;
gettimeofday(&tv, NULL);
int usec = tv.tv_usec;
srand48(usec);
if (n > 1) {
size_t i;
for (i = n - 1; i > 0; i--) {
size_t j = (unsigned int) (drand48()*(i+1));
int t = array[j];
array[j] = array[i];
array[i] = t;
}
}
}
static inline void shuffle(size_t n, int arr[])
{
size_t rng;
size_t i;
int tmp[n];
int tmp2[n];
memcpy(tmp, arr, sizeof(int) * n);
bzero(tmp2, sizeof(int) * n);
srand(time(NULL));
i = 0;
while (i < n)
{
rng = rand() % (n - i);
while (tmp2[rng] == 1)
++rng;
tmp2[rng] = 1;
arr[i] = tmp[rng];
++i;
}
}
3, 4, 1, 0, 2, 7, 6, 9, 8, 5
#include <stdlib.h>
#include <time.h>
void shuffle(int aArray[], int cnt){
int temp, randomNumber;
time_t t;
srand((unsigned)time(&t));
for (int i=cnt-1; i>0; i--) {
temp = aArray[i];
randomNumber = (rand() % (i+1));
aArray[i] = aArray[randomNumber];
aArray[randomNumber] = temp;
}
}