C编程语言中整数数组中的唯一随机数

时间:2009-10-22 15:51:13

标签: c algorithm random

  

可能重复:
  Unique random numbers in O(1)?

如何在C?

中填充具有唯一值(无重复项)的整数数组
int vektor[10];   

for (i = 0; i < 10; i++) {
    vektor[i] = rand() % 100 + 1;
}

//No uniqueness here

9 个答案:

答案 0 :(得分:72)

答案 1 :(得分:5)

在您的示例中(选择1到100之间的10个唯一随机数),您可以创建一个数字为1到100的列表,使用随机数生成器对列表进行随机播放,然后从列表中获取前10个值

int list[100], vektor[10];
for (i = 0; i < 100; i++) {
    list[i] = i;
}
for (i = 0; i < 100; i++) {
    int j = i + rand() % (100 - i);
    int temp = list[i];
    list[i] = list[j];
    list[j] = temp;
}
for (i = 0; i < 10; i++) {
    vektor[i] = list[i];
}

根据下面的cobbal评论,最好只说:

for (i = 0; i < 10; i++) {
    int j = i + rand() % (100 - i);
    int temp = list[i];
    list[i] = list[j];
    list[j] = temp;

    vektor[i] = list[i];
}

现在设置列表是O(N),但O(M)选择随机元素。

答案 2 :(得分:3)

我认为这样做(我没有尝试过构建它,因此语法错误可以作为读者练习)。可能有更优雅的方式,但这是强力解决方案:

int vektor[10];    
int random;
int uniqueflag;
int i, j

for(i = 0; i < 10; i++) {
     do {
        /* Assume things are unique... we'll reset this flag if not. */
        uniqueflag = 1;
        random = rand() % 100+ 1;
        /* This loop checks for uniqueness */
        for (j = 0; j < i && uniqueflag == 1; j++) {
           if (vektor[j] == random) {
              uniqueflag = 0;
           }
        }
     } while (uniqueflag != 1);
     vektor[i] = random;
}

答案 3 :(得分:3)

简单地生成随机数并查看它们是否正常通常是解决此问题的一种不好的方法。这种方法采用所有可能的值,将它们混洗,然后进入前十。这直接类似于改组一副牌并处理顶部。

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

#define randrange(N) rand() / (RAND_MAX/(N) + 1)

#define MAX 100        /* Values will be in the range (1 .. MAX) */
static int vektor[10];
int candidates[MAX];

int main (void) {
  int i;

  srand(time(NULL));   /* Seed the random number generator. */

  for (i=0; i<MAX; i++)
    candidates[i] = i;

  for (i = 0; i < MAX-1; i++) {
    int c = randrange(MAX-i);
    int t = candidates[i];
    candidates[i] = candidates[i+c];
    candidates[i+c] = t;
  }

  for (i=0; i<10; i++)
    vektor[i] = candidates[i] + 1;

  for (i=0; i<10; i++)
    printf("%i\n", vektor[i]);

  return 0;
}

有关详情,请参阅comp.lang.c FAQ list question 13.19进行改组,question 13.16了解有关生成随机数的信息。

答案 4 :(得分:0)

一种方法是检查数组是否已经包含新的随机数,如果已经包含新的随机数,请创建一个新的随机数,然后重试。

这打开了(随机;))你永远不会得到一个不在数组中的数字的可能性。因此,您应该计算检查数字是否已经在数组中的次数,如果计数超过MAX_DUPLICATE_COUNT,则抛出异常左右:)(编辑,看到你在C中。忘记异常部分:)返回错误代码:P)

答案 5 :(得分:0)

快速解决方案是创建一个包含初始化为零的所有可能数字的掩码数组,并在生成该数字时设置一个条目

int rand_array[100] = {0};
int vektor[10];   
int i=0, rnd;
while(i<10) {
    rnd = rand() % 100+ 1;
    if ( rand_array[rnd-1] == 0 ) {
        vektor[i++] = rnd;
        rand_array[rnd-1] = 1;
    }
}

答案 6 :(得分:0)

分别生成第一个和第二个数字。 如果需要,稍后将它们洗牌。 (来自记忆的语法)

int vektor[10];
int i = 0;

while(i < 10) {
  int j = rand() % 10;
  if (vektor[j] == 0) { vektor[j] = rand() % 10 + j * 10; i ++;}
}

然而,数字将几乎相隔n,0 <0。 n&lt; 10。

否则,您需要对数字进行排序(O(n log n)),以便快速检查新生成的状态(O(log n))。

答案 7 :(得分:0)

这是一个O(M)平均时间方法。

方法:如果M <= N / 2,则使用过程S(M,N)(下面)生成结果数组R,并返回R.如果M> N / 2,使用程序S(NM,N)生成R,然后计算X = {1..M}\R [{1..M}中R的补集],用Fisher-Yates shuffle随机抽取X [时间O( M)],并返回X.

在M>在N / 2情况下,其中O(M)== O(N),有几种快速计算补码的方法。在下面显示的代码中,为简洁起见,我仅包括在main()中内联编码的过程S(M,N)的示例。 Fisher-Yates shuffle是O(M),并在相关问题#196017的主要答案中说明。其他以前的相关问题:#158716#54059

当M Coupon-collector's problem中所述,期望E(t_k)是k H_k,E(t_ {k / 2})= k (H_k - H_ {k / 2})或关于k *(ln(k)-ln(k / 2)+ O(1))= k *(ln(k /(k / 2))+ O(1))= k *( ln(2)+ O(1))= O(k)。

程序S(k,N):[此程序的主体是在下面的代码中注释“Gen M不同随机数”之后的十几行。]分配并初始化三个M + 1元素整数数组H, L和V为全-1值。对于i = 0到M-1:将随机值v放入V [i]并进入标记节点V [-1]。从H [v%M]中获取M个列表头中的一个并按照该列表直到找到与v的匹配。如果匹配在V [-1],则v是新值;所以更新列表头H [v%M]并列出链接L [i]。如果匹配不在V [-1],则获取并测试另一个v等。

每个“跟随列表”步骤具有预期成本O(1),因为除了最后一步之外的每个步骤,平均列表长度小于1.(在处理结束时,M列表包含M个元素,因此平均长度逐渐变小正好上升到1。)

 // randomMofN - jiw 8 Nov 2011     
 // Re: https://stackoverflow.com/questions/1608181/
 #include <stdlib.h>
 #include <stdio.h>
 int main(int argc, char *argv[]) {
   int h, i, j, tM, M, N, par=0, *H, *L, *V, cxc=0;
   // Get M and N values
   ++par; M = 42;  if (argc > par) M = atoi(argv[par]);
   ++par; N = 137; if (argc > par) N = atoi(argv[par]);
   tM = 3*M+3;
   H = malloc(tM*sizeof(int));
   printf ("M = %d,  N = %d  %s\n", M, N, H?"":"\nmem error");
   if (!H) exit(13);
   for (i=0; i<tM; ++i)           // Init arrays to -1's
     H[i] = -1;
   L = H+M;  V = L+M;

   // Gen M distinct random numbers
   for (i=0; i<M; ++i) {
     do {
       ++cxc;                     // complexity counter
       V[-1] = V[i] = random()%N;
       h = V[i]%M;                // h = list-head index
       j = H[h];
       while (V[j] != V[i])
         j = L[j];
     } while (j>=0);
     L[i] = H[h];
     H[h] = i;
   }

   // Print results
   for (j=i=0; i<M; ++i) {
     j += printf ("%4d ", V[i]);
     if (j>66) j = printf ("\n");
   }
   printf ("\ncxc %d\n", cxc);
   return 0;
 }

答案 8 :(得分:0)

我喜欢Floyd算法。

但我们可以将0中的所有随机数转换为M(不是in):

#define M 10
#define N 100    

unsigned char is_used[N] = { 0 }; /* flags */
int in, im;

im = 0;

for (in = N - M; in < N && im < M; ++in) {
  int r = rand() % (N + 1); /* generate a random number 'r' */

  while (is_used[r])
  {
     /* we already have 'r' */
     r = rand() % (N + 1);
  }
  vektor[im++] = r + 1; /* +1 since your range begins from 1 */
  is_used[r] = 1;
}

assert(im == M);