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

查看:28
本文介绍了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
", i);
        i = myRandom (-1);
    }
    printf ("Final  = %3d
", 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
", i);
        i = myRandom (-1, &pPool);
    }
    printf ("Final  = %3d
", i);
    return 0;
}

从修改后的main()可以看出,你需要先初始化一个int指针到NULL然后把它的地址传给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天全站免登陆