【问题标题】:Generating unique random numbers in C在 C 中生成唯一的随机数
【发布时间】:2011-02-21 09:44:42
【问题描述】:

我尝试在 C 中生成 10 个唯一的随机数。我有一个包含 10 个数字的数组 numout[],但这会在一段时间后出现“分段错误”。

代码是:

int i,j,numout[10],randnum;

void main()
{
    srand(time(NULL));  
    for(i=0;i<10;i++)
    {
        numout[i]=generate();
        printf("%d",numout[i]);
        fflush(stdout);
        sleep(1);
        printf("\b");
    }
}
int generate()
{
    randnum=1+(int)(rand()*mul_val/(RAND_MAX+1.0));
    for(j=0;j<i;j++)
    {
        if(randnum==0 || randnum==numout[j])
        {
            randnum=generate();     
        }
    }
    return(randnum);
}

【问题讨论】:

  • 我们看不到您如何声明numout。这段代码甚至无法编译。这些数字在什么意义上是独一无二的?
  • numout[]的声明在哪里,“i”和“mul_val”是什么?
  • -1 ... 而i是什么,由于代码不完整,无法分辨出什么问题
  • 我用完整的代码编辑了。

标签: c


【解决方案1】:

认真地扔掉那段代码。您需要一个洗牌算法,而不是一段检查旧值是否重复的代码。随着您的游泳池用完,按照您的方式进行操作最终会花费越来越长的时间。洗牌算法的优点是它不会随着池变小而降级。

这是我在回答另一个问题时使用的一段代码。它维护一个数字列表,当它向您返回一个随机数字时,它会将其从列表中删除并减少下一个随机选择的计数。

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

#define ERR_NO_NUM -1
#define ERR_NO_MEM -2

int myRandom (int size) {
    int i, n;
    static int numNums = 0;
    static int *numArr = NULL;

    // Initialize with a specific size.

    if (size >= 0) {
        if (numArr != NULL)
            free (numArr);
        if ((numArr = malloc (sizeof(int) * size)) == NULL)
            return ERR_NO_MEM;
        for (i = 0; i  < size; i++)
            numArr[i] = i;
        numNums = size;
    }

    // Error if no numbers left in pool.

    if (numNums == 0)
       return ERR_NO_NUM;

    // Get random number from pool and remove it (rnd in this
    //   case returns a number between 0 and numNums-1 inclusive).

    n = rand() % numNums;
    i = numArr[n];
    numArr[n] = numArr[numNums-1];
    numNums--;
    if (numNums == 0) {
        free (numArr);
        numArr = 0;
    }

    return i;
}

int main (void) {
    int i;

    srand (time (NULL));
    i = myRandom (20);
    while (i >= 0) {
        printf ("Number = %3d\n", i);
        i = myRandom (-1);
    }
    printf ("Final  = %3d\n", i);
    return 0;
}

示例输出显示了它的实际效果:

Number =  19
Number =  10
Number =   2
Number =  15
Number =   0
Number =   6
Number =   1
Number =   3
Number =  17
Number =  14
Number =  12
Number =  18
Number =   4
Number =   9
Number =   7
Number =   8
Number =  16
Number =   5
Number =  11
Number =  13
Final  =  -1

使用非负池大小调用它,它会设置一个新序列并返回第一个随机值。之后,您可以使用-1 调用它,它将从池中获取下一个随机的唯一编号。当池耗尽时,它将返回-1。

包含此代码的other answer 有一个可以维护多个池的版本,如果您希望能够在线程代码中使用此函数。

【讨论】:

    【解决方案2】:

    当您用完堆栈空间时,您将遇到分段错误。您的代码是递归的(即generate() 调用generate())。所以当你用完未使用的随机数时,它会永远调用自己。

    但是,我不建议对您的代码进行修复,因为您确实需要从头开始重新编写它。按照 paxdiablo 的例子。

    【讨论】:

      【解决方案3】:

      如果您需要大量唯一随机数,您应该考虑使用 LFSR 方法。 LFSR 生成唯一随机数,除非整个池用尽,否则不会重复,因此 32 位 LFSR 将生成 2^32 - 1 个唯一随机数 -- 它不会生成 0。编码很简单,请查看谷歌。

      【讨论】:

        【解决方案4】:
        The program below stores n unique random numbers i.e, from [1 to n] in an array.
        
        #include<iostream.h>
        #include<conio.h>
        
        void main()
        {
        
        int i, j, Array[100];
        cout<<"Enter value of n : ";     //upper limit
        cin>>n;
        
        randomize();
        
        int rnd;
        
        Array[1]=rand()%n+1;
        
        for(i=2;i<=n;i++)
        {
            rnd=rand()%n+1;
        
             for(j=1;j<i;j++)
             {
                if(rnd==Array[j])
                {
                    i--;
                    break;
                }
            }
        
                if(j>=i)
                Array[i]=rnd;
        }
        
        
        
        //for printing from random numbers from 1 to n
        for(i=1;i<=n;i++)
        cout<<Array[i]<<"\n";
        
        getch();
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-01-06
          • 1970-01-01
          相关资源
          最近更新 更多