如何生成不同整数的数组

时间:2019-04-21 18:52:30

标签: c

我一直在尝试制作一个由极不同的随机整数组成的数组,其中25个介于1到75之间。已经陷入无限循环。非常感谢!

我试图寻找解决方案,但我要么不理解它们,要么就没有找到适合我水平的东西。 顺便说一句,我确保我使用了srand(time(NULL));

for (i = 0; i < 25; i++)
    {
        while (k != 1)
        {
            arr[i] = rand() % 75 + 1;
            for (j = 0; j < 25; j++)
            {
                if (arr[i] == arr[j])
                {
                    k++;
                }
            }
        }
        k = 0;
    }

整个代码:

/*********************************
* Class: MAGSHIMIM C2            *
* Week:                          *
* Name:                          *
* Credits:                       *
**********************************/

#include <stdio.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
int main(void)
{
    srand(time(NULL));
    int i = 0;
    int j = 0;
    int k = 0;
    int arr[25] = { 0 };
    for (i = 0; i < 25; i++)
    {
        while (k != 1)
        {
            arr[i] = rand() % 75 + 1;
            for (j = 0; j < 25; j++)
            {
                if (arr[i] == arr[j])
                {
                    k++;
                }
            }
        }
        k = 0;
    }
    for (i = 0; i < 25; i++)
    {
        printf("%d", arr[i]);
    }
    getchar();
    return 0;
}

expecetd:一个不错的差分数组,但是我遇到了无限循环。

5 个答案:

答案 0 :(得分:1)

一种方法是在所需范围内制造一个池或一包数字,然后从中选择。重复检查以查看是否已选择号码并不困难,并且效率更高。您修改后的程序现在为:

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

#define ARRLEN  25          // how many to pick
#define NUMBERS 75          // range of available numbers
#if NUMBERS < ARRLEN        // precaution
    #error Impossible job!
#endif

int cmp(const void *a, const void *b)
// optional, for qsort
{
    return *(int *)a - *(int *)b;
}

int main(void)
{
    int arr[ARRLEN];                    // final array
    int bag[NUMBERS];                   // bag of available numbers
    int avail = NUMBERS;                // size of bag available
    srand((unsigned)time(NULL));

    // prepare the bag of available numbers
    for(int i = 0; i < NUMBERS; i++) {
        bag[i] = i + 1;
    }

    // fill the array with values from the bag
    for(int i = 0; i < ARRLEN; i++) {
        int index = rand() % avail;     // random index into array
        arr[i] = bag[index];            // take that number

        avail--;
        bag[index] = bag[avail];        // replace with the one from the top
    }

    // just to check, sort the array, can be deleted
    qsort(arr, ARRLEN, sizeof arr[0], cmp);

    // output the result
    for (int i = 0; i < ARRLEN; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    getchar();
    return 0;
}

我对数组进行了排序,以使其易于查看是否存在重复项。可以删除qsort行和cmp函数。

三个运行的程序输出

6 7 8 9 12 16 17 19 21 27 31 35 43 46 47 50 51 53 59 64 65 66 70 71 72
2 6 7 14 17 23 24 25 30 31 32 34 36 37 45 58 59 61 65 68 69 71 73 74 75
5 10 13 18 20 21 25 30 34 36 39 40 41 43 49 50 54 58 60 63 64 66 67 72 75

答案 1 :(得分:0)

  

...但是我遇到了无限循环。

只需替换

    while (k != 1)
    {
        arr[i] = rand() % 75 + 1;
        for (j = 0; j < 25; j++) {
          ...
        }
    }
    k = 0;

作者

do
{
  k = 0;
  arr[i] = rand() % 75 + 1;
  for (j = 0; j < 25; j++) {
     ...
  }
} while (k != 1);

请注意,检查所有数组(包括未由随机值设置的条目)也是没有用的,因此可以是:

do
{
  k = 0;
  arr[i] = rand() % 75 + 1;
  for (j = 0; j < i; j++)
  {
    if (arr[i] == arr[j])
    {
      k++;
    }
  }
} while (k != 0);

因为现在 j 无法将 i 赋值,所以测试是(k != 0)而不是(k != 1)

或更好,因为当找到相同的值时,没有理由继续

do
{
  arr[i] = rand() % 75 + 1;
  for (j = 0; j < i; j++)
  {
    if (arr[i] == arr[j])
      break;
  }
} while (j != i);

要清楚地看到这些值,还应在它们之间添加一个空格并添加最后一个换行符:

for (i = 0; i < 25; i++)
{
    printf("%d ", arr[i]);
}
putchar('\n');

这些更改,编译和执行之后:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra -Wall r.c
pi@raspberrypi:/tmp $ ./a.out
74 60 16 65 54 19 55 45 41 24 39 59 66 36 27 22 68 49 29 14 28 5 71 56 72 

pi@raspberrypi:/tmp $ ./a.out
16 34 62 29 74 41 3 43 69 17 61 22 28 59 7 65 5 46 60 20 66 14 49 54 45 

pi@raspberrypi:/tmp $ 

修改

实现很简单,但是以这种方式查找尚未使用的值可能会花费一些时间,并且允许值的范围越接近返回值的数量,所需的时间就越长。因此,与允许的值范围相比,当返回的值很少时,这种解决方案是很好的。

关于风向标的有趣提议则相反,对 rand 的调用次数仅等于要返回的值的数量,但是允许值的范围越大,则值越大数组 bag 很大,可能会溢出内存大小。

对于25个从1到75的值来说,Weather Vane的解决方案更好。。。甚至我的提议似乎只需要0.001秒就可以覆盖我的树莓派了,所以几乎什么都没有

答案 2 :(得分:0)

int *fillint(int *arr, size_t size)
{
    int added = 0;
    int pos = 0
    while(pos != size)
    {
        int rv;
        do
        {
            added = 1;
            rv = rand();

            for(size_t index = 0; index < pos; index++)
            {
                if(arr[index] == rv)
                {
                    added = 0;
                    break;
                }
            }
        }while(!added)
        arr[pos++] = rv;
    }
    return arr;
}

答案 3 :(得分:0)

Weather Vane的 bag 方法的另一个细微变化,不是准备一个包含所有可用数字的袋子,而是简单地声明一个数组,该数组的最大元素数等于对所有对象初始化的可接受数字范围零(例如int arr[75] = {0};)。无需填充数组,每次使用该数字填充数组时,您只需将元素增加1。

要确保仅使用唯一数字,请检查数组的相应元素是否为零,如果为零,请使用该数字并递增该元素。如果它不是零,则说明该数字已被使用-请生成另一个数字,然后重试。

例如,将数组的整数个数为25,将任何一个整数的最大值为75,您可以这样做:

#define NINT 25
#define MAXI 75
...
    int arr[NINT],
        seen[MAXI] = {0};
    ...
    for (int i = 0; i < NINT; i++) {    /* for each needed element */
        int tmp = rand() % MAXI + 1;    /* generate a random in range */
        while (seen[tmp-1])             /* has been seen/used yet? */
            tmp = rand() % MAXI + 1;    /* if so, generate another */
        seen[tmp-1]++;                  /* incement element */
        arr[i] = tmp;                   /* assign unique value to arr */
    }

注意seen索引被映射为tmp-1以映射到有效索引0-74,而为tmp生成的数字将是1-75使用rand() % MAXI + 1。您可以容纳这种类型的映射所需的任何范围,使用1000001 - 1000075中的数字范围仍然只需要包含75个元素的seen数组。 )

要输出按顺序使用的数字,只需要输出与seen数组(+1的每个非零元素相对应的索引(1-75即可映射回{{1} }值范围),例如

    for (int i = 0; i < MAXI; i++)
        if (seen[i])
            printf (" %d", i + 1);
    putchar ('\n');

将其完全放在一个简短的示例中,您可以这样做:

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

#define NINT 25
#define MAXI 75

int main (void) {

    int arr[NINT],
        seen[MAXI] = {0};
    srand (time(NULL));

    for (int i = 0; i < NINT; i++) {    /* for each needed element */
        int tmp = rand() % MAXI + 1;    /* generate a random in range */
        while (seen[tmp-1])             /* has been seen/used yet? */
            tmp = rand() % MAXI + 1;    /* if so, generate another */
        seen[tmp-1]++;                  /* incement element */
        arr[i] = tmp;                   /* assign unique value to arr */
    }

    puts ("array:");
    for (int i = 0; i < NINT; i++) {
        if (i && i % 5 == 0)
            putchar ('\n');
        printf (" %2d", arr[i]);
    }

    puts ("\n\nused:");
    for (int i = 0; i < MAXI; i++)
        if (seen[i])
            printf (" %d", i + 1);
    putchar ('\n');
}

注意:显然,可见数组的大小将限制为可用的堆栈大小,因此,如果所需数字范围超出了用seen可用的内存, >自动存储类型,则需要将seen设置为具有已分配存储类型的数组。

使用/输出示例

$ ./bin/randarr25-75
array:
  1 18 70 26 75
 29 31 58 22  9
  5 13  3 25 35
 40 48 44 57 56
 60 50 71 67 43

used:
 1 3 5 9 13 18 22 25 26 29 31 35 40 43 44 48 50 56 57 58 60 67 70 71 75

无论您使用袋子还是数组来跟踪看到的数字,结果都是相同的。没有人比另一个更好。将它们都添加到您的C工具箱中。

答案 4 :(得分:-1)

在内部for循环中,对j进行迭代,直到j

此外,每次检查以前的出现次数时,请将k的值初始化为零,这使代码更易于阅读。

如果发现一个事件,只需中断一下,即使使较大的值有所不同,它也可使算法运行得更快。

类似这样的东西:

for (i = 0; i < 25; i++)
{
    k = 1;
    while (k != 0)
    {
        arr[i] = rand() % 75 + 1;
        k = 0; 

        for (j = 0; j < i; j++)
        {
            if (arr[i] == arr[j])
            {
                k++;
                break;
            }
        }
    }
}