Objective-C中的非重复随机数 [英] Non repeating random numbers in Objective-C

查看:85
本文介绍了Objective-C中的非重复随机数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用

for (int i = 1, i<100, i++)
    int i = arc4random() % array count;

但是我每次都在重复.如何填充从范围中选择的int值,以便在程序循环时不会收到任何重复信息?

but I'm getting repeats every time. How can I fill out the chosen int value from the range, so that when the program loops I will not get any dupe?

推荐答案

这听起来像是要改组集合,而不是真正的"随机性.只需创建一个所有位置都与数字匹配的数组并初始化一个计数器:

It sounds like you want shuffling of a set rather than "true" randomness. Simply create an array where all the positions match the numbers and initialize a counter:

num[ 0] =  0
num[ 1] =  1
: :
num[99] = 99
numNums = 100

然后,每当需要随机数时,请使用以下方法:

Then, whenever you want a random number, use the following method:

idx = rnd (numNums);       // return value 0 through numNums-1
val = num[idx];            // get then number at that position.
num[idx] = val[numNums-1]; // remove it from pool by overwriting with highest
numNums--;                 //   and removing the highest position from pool.
return val;                // give it back to caller.

这将从不断减少的池中返回一个随机值,从而保证不会重复.当然,您将必须谨防池中的池逐渐减少到零大小,并智能地重新初始化池.

This will return a random value from an ever-decreasing pool, guaranteeing no repeats. You will have to beware of the pool running down to zero size of course, and intelligently re-initialize the pool.

这是一个更具确定性的解决方案,而不是保留一个已用数字列表并继续循环直到找到不在该列表中的数字为止.这种算法的性能会随着池的变小而降低.

This is a more deterministic solution than keeping a list of used numbers and continuing to loop until you find one not in that list. The performance of that sort of algorithm will degrade as the pool gets smaller.

使用静态值的C函数应该可以解决问题.呼叫

A C function using static values something like this should do the trick. Call it with

int i = myRandom (200);

设置池(使用零或更大的数字指定大小)或

to set the pool up (with any number zero or greater specifying the size) or

int i = myRandom (-1);

以从池中获取下一个数字(任何负数都足够).如果该函数不能分配足够的内存,它将返回-2.如果池中没有剩余数字,它将返回-1(此时,您可以根据需要重新初始化池).这是带有单元测试主要功能的功能,供您试用:

to get the next number from the pool (any negative number will suffice). If the function can't allocate enough memory, it will return -2. If there's no numbers left in the pool, it will return -1 (at which point you could re-initialize the pool if you wish). Here's the function with a unit testing main for you to try out:

#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

请记住,由于它使用静态,因此如果要维护自己的单独池,从两个不同位置进行调用是不安全的.如果是这种情况,则将用将属于"调用者的缓冲区(保留计数和池)替换为静态对象(为此目的,可以传递双指针).

Keep in mind that, because it uses statics, it's not safe for calling from two different places if they want to maintain their own separate pools. If that were the case, the statics would be replaced with a buffer (holding count and pool) that would "belong" to the caller (a double-pointer could be passed in for this purpose).

而且,如果您正在寻找多个池"版本,出于完整性考虑,我将其包含在此处.

And, if you're looking for the "multiple pool" version, I include it here for completeness.

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

#define ERR_NO_NUM -1
#define ERR_NO_MEM -2

int myRandom (int size, int *ppPool[]) {
    int i, n;

    // Initialize with a specific size.

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

    // Error if no numbers left in pool.

    if (*ppPool == NULL)
       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() % (*ppPool)[0];
    i = (*ppPool)[n+1];
    (*ppPool)[n+1] = (*ppPool)[(*ppPool)[0]];
    (*ppPool)[0]--;
    if ((*ppPool)[0] == 0) {
        free (*ppPool);
        *ppPool = NULL;
    }

    return i;
}

int main (void) {
    int i;
    int *pPool;

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

从修改后的main()中可以看到,您需要首先初始化指向NULLint指针,然后将其地址传递给myRandom()函数.这样,每个客户端(代码中的位置)都可以拥有自己的池,该池将自动分配和释放,尽管您仍然可以共享池.

As you can see from the modified main(), you need to first initialise an int pointer to NULL then pass its address to the myRandom() function. This allows each client (location in the code) to have their own pool which is automatically allocated and freed, although you could still share pools if you wish.

这篇关于Objective-C中的非重复随机数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆