C语言中的洗牌数组

C语言中的洗牌数组,c,arrays,C,Arrays,我正在寻找一个ANSIC中的函数,它可以像PHP的shuffle()一样随机化数组。有这样一个函数吗?还是我必须自己写?如果我必须自己写,那么最好/最有效的方法是什么 到目前为止,我的想法是: 例如,在数组中迭代100次,并将一个随机索引与另一个随机索引交换 创建一个新数组,并使用第一个数组中的随机索引填充该数组,每次检查是否已获取索引(性能=0复杂性=严重) 在C标准中没有随机化数组的函数 看看Knuth,他有这项工作的算法 或者看看宾利-编程珍珠或更多编程珍珠 或者看看几乎所有的算法书

我正在寻找一个ANSIC中的函数,它可以像PHP的
shuffle()
一样随机化数组。有这样一个函数吗?还是我必须自己写?如果我必须自己写,那么最好/最有效的方法是什么

到目前为止,我的想法是:

  • 例如,在数组中迭代100次,并将一个随机索引与另一个随机索引交换
  • 创建一个新数组,并使用第一个数组中的随机索引填充该数组,每次检查是否已获取索引(性能=0复杂性=严重)

在C标准中没有随机化数组的函数

  • 看看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;
    }
}