六个数字组合的随机数生成

问题描述 投票:0回答:4

我正在做一个伪随机数生成器,它创建 100 个从 1 到 56 范围内的 6 个数字的组合,不重复,然后将它们保存在文本文件中。像这样:

33 28 46 7 30 57 
15 29 43 41 16 21 
11 43 7 18 31 25 
36 32 19 42 47 33 
46 13 14 1 28 25 
33 14 55 43 29 13 
30 14 12 45 46 32 
56 31 54 32 20 21 
10 52 40 57 31 14 
28 44 15 47 57 45 
...

这是我的代码,但我觉得它有点太大了,特别是检查数字是否重复的部分

// Including C Standard Libraries
#include <stdint.h>  
#include<stdio.h> 
#include<stdlib.h> 
#include<time.h> 

int main() 
{ 
    // Initialing Random Generation C Library
    srand(time(NULL)); 

    // Variables for PRNG Loop
    uint16_t i;  
    uint8_t j; 

    uint8_t x[6] = {0,0,0,0,0,0};

    // Opening File to save Results
    FILE *fp;
    fp = fopen("combinations.txt", "w+"); 

    // PRNF Loop
    for(i = 0; i<100; i++)  // Numbers of Combinations 
    {
        for(j = 0; j<6; j++)  // Number of Elements of the Combinations
        {
            x[j] = rand() % 57 + 1;  // Generating Random Number

            // Avoiding Repetition of Numbers
            if ( j==1)
            {
                while(x[1] == x[0])
                {
                    x[1] = rand() % 57 + 1;
                }
            }
            if ( j==2)
            {
                while(x[2] == x[0] || x[2] == x[1])
                {
                    x[2] = rand() % 57 + 1;
                }
            }
            if ( j==3)
            {
                while(x[3] == x[0] || x[3] == x[1] || x[3] == x[2] )
                {
                    x[3] = rand() % 57 + 1;
                }
            }
            if ( j==4)
            {
                while(x[4] == x[0] || x[4] == x[1] || x[4] == x[2] || x[4] == x[3] )
                {
                    x[4] = rand() % 57 + 1;
                }
            }
            if ( j==5)
            {
                while(x[5] == x[0] || x[5] == x[1] || x[5] == x[2] || x[5] == x[3] || x[5] == x[4] )
                {
                    x[5] = rand() % 57 + 1;
                }
            }


            fprintf(fp, "%d", x[j]);  // Saving Random Number in File
            fprintf(fp, " "); 
        } 

        fprintf(fp, "\n");  // Saving Newline  

        for (int i = 0; i < 6; ++i)
        {
            x[i] = 0;
        }    

    }

    fclose(fp);
} 

有没有办法简化代码?

c file random combinations
4个回答
1
投票

您可以通过使用循环迭代当前集来简化唯一性测试,其中对于所有所有前面值,您测试当前值的唯一性:

            // Generate a unique random number
            bool unique = false ;
            while( !unique )
            {
                x[j] = rand() % RANGE + 1;  // Random 1 to 56

                // Test uniqueness from all preceding values in 
                // the set (x[0] is always unique)
                unique = true ;
                for( int k = 1; unique && k < j; k++ )
                {
                    unique = x[k] != x[j] ;
                }
            }

请注意,如果设置的长度很大,那么扫描所有前面的值方法可能不是最佳的,但在这种情况下似乎合理且简单。

既然您(有点)要求,可以通过以下方式进一步改进代码(例如 - 合并这些的代码如下):

  • 消除魔法数字
  • 初始化数组的第一个成员,将所有剩余成员初始化为零。
  • 在实例化时初始化(而不是定义并单独分配)。
  • 在尽可能窄的范围内实例化 - 并非全部在函数顶部
  • 不要打开您不使用的访问类型的文件(“w”而不是“w+”)
  • 错误检查I/O功能
  • 不必要时不要使用 stdint 类型 - 算术运算经常导致隐式转换为
    int
    。使用
    int
    除非有充分的理由不这样做以避免意外。使用 stdint 的充分理由包括符合某些文件格式或通信协议,或者匹配设备驱动程序中的寄存器宽度。不在这里。
  • 例如测试并修复错误 (
    rand() % 57 + 1
    )。
  • 避免重复 - 使用循环(本例中的唯一性测试)。
  • 只在评论中说一些有用的内容。如果代码是自记录的,请保持安静。如果不明显,请解释 - 不要简单地重复任何人都可以从代码中看到的内容(例如“生成随机数”)
  • 不要用现在进行时写注释(无“ing”动词)。好吧,这并不是真正的改进,只是我觉得烦人的事情;-)。源代码描述了程序做的事情,而不是它正在做什么。
  • 不要在每行最后一个值之后写入多余的空格。
  • 删除不必要的代码 - 例如最后的循环归零
    x[]
  • 如果你承诺返回一个值,那就返回一个值。
#include <stdbool.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 

#define SET_LENGTH 6    // Number of values in each set
#define SET_COUNT 100   // Number of sets
#define RANGE 56        // Range of each value 1 to RANGE

int main() 
{ 
    // Initialing Random Generation C Library
    srand(time(NULL)); 

    int x[SET_LENGTH] = {0};

    // Open file
    FILE* fp = fopen( "combinations.txt", "w" ) ; 
    if( fp != NULL )
    {
        // For each random number set...
        for( int i = 0; !ferror( fp ) && i < SET_COUNT; i++ )
        {
            // For each number in the set...
            for( int j = 0; j < SET_LENGTH; j++) 
            {
                // Generate a unique random number
                bool unique = false ;
                while( !unique )
                {
                    x[j] = rand() % RANGE + 1;  // Random 1 to 56

                    // Test uniqueness from all preceding values in 
                    // the set (x[0] is always unique)
                    unique = true ;
                    for( int k = 1; unique && k < j; k++ )
                    {
                        unique = x[k] != x[j] ;
                    }
                }

                // Write value to file. 
                // Space separated values with newline end.
                fprintf(fp, "%d%c",x[j], 
                        j < SET_LENGTH - 1? ' ' : '\n' ) ;
            } 
        }
    }

    fclose(fp);

    return 0 ;
} 

这里没有“改进”的是当

rand() % n
n
不是
RAND_MAX+1
的因子时发生的“随机偏差”问题。如果随机性很关键,您可能需要考虑这一点。


0
投票

您可以通过使用已用值数组来简化。

例如添加:

uint8_t used[56] = {0};

第一个和第二个

for
循环之间

然后这样选择您的值:

do
{
  x[j] = rand() % 56 + 1;  // Generating Random Number
} while (used[x[j]-1] != 0);
used[x[j]-1] == 1;

当使用一个值时,我们将 1 放在数组中的该位置。 当寻找一个值时,我们循环直到找到一个空槽。

要使用随机数组,您可以这样做。

创建一个包含第一个

for
循环之前的所有值的数组:

uint8_t shuffle[56] = { 1, 2, 3, 4, 5, 6, 7, /* ... */ 54, 55, 56 };

然后这样选择你的价值观:

uint8_t pos = rand() % (56-j);  // Generating Random Number Location
x[j] = shuffle[pos];  // Selecting Random Number
shuffle[pos] = shuffle[55];
shuffle[55] = x[j];

0
投票

为什么不类似:

#define NUM_RANDOM_NUMBERS 56

// Include all possible numbers.
int range[NUM_RANDOM_NUMBERS];

// Record current size of the array (this could be dynamic if we don't know the starting size...
int curSize = NUM_RANDOM_NUMBERS;

int getRandom()
{
    // If we are called with curSize at 0 or less, this is an error condition.  We have no numbers to return.
    assert(curSize > 0);

    // Get a number from our table and place it into a return Value.
    int index = random() % curSize;
    int retValue = range[index];

    // Move all the values above the index over the swapped out value.
    // memmove would probably be more efficient.
    for(int i = index; i < curSize - 1; i++) 
        range[i] = range[i+1];

    // Reduce the size of our pool of numbers.
    curSize--;

    // Return the value;
    return retValue;
}

int main()
{
    // Load the range pool with all the possible numbers.
    for(int i=0; i<NUM_RANDOM_NUMBERS; i++)
    {
        range[i] = i+1;    
    }

    // Now retreive them in random order.
    for(int i=0; i<NUM_RANDOM_NUMBERS; i++)
    {
        printf("%d \n", getRandom());
    }

    return 0;
}

请注意,我用此方法调用 random 的次数最少。该运行时间最长的部分可能是范围池中内存的移动,但它将运行确定的时间量。


0
投票

您可以使用下面的这个函数从一组 N 个整数中生成 k 个整数的组合。 它在变量 arr 中返回从 0 到 N-1 的 k 个值,该变量是一个数组。

void random_combination(int *arr, int N, int k){
    // function returning shuffled indexes 
    // arr: array to receive shuffled indexes
    // N: size of the array
    // k: number of index to return. Must be lower or equal to N
    int used[N];            // storage of already picked indexes
    for (int i=0; i<N; i++) used[i]=0;
    int cnt;                // counter for unused indexes
    int r;                  // holds the random number
    for (int i=0; i<k; i++){
        r = rand() % (N-i);     // generate random number modulo the remaining number of unused indexes
        cnt = 0;
        for (int j=0; j<N; j++){    // going through each used/unused indexes
            if (used[j]==0){
                if (cnt==r){
                    used[j] = 1;
                    arr[i] = j;
                    //printf("r: %d j: %d\n", r, j); // uncomment me to see what I do.
                    break;
                }
                cnt++;  
            }
        }
    }
}

对于此处的示例,请按如下方式使用

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

// copy paste the above function here

int main(int argc, char *argv[]){

    srand(time(0));
    int NN = 56;
    int k = 6;
    int arr[NN];
    random_combination(arr, NN, k);
    for (int i=0; i<k; i++){
        printf(" %d", arr[i]+1);
        // do whatever is needed with arr[i]+1 here
    }
    printf("\n");
}
© www.soinside.com 2019 - 2024. All rights reserved.