Звучит так, будто вы хотите перетасовать сет, а не «истинную» случайность. Просто создайте массив, в котором все позиции соответствуют номерам, и инициализируйте счетчик:
num[ 0] = 0
num[ 1] = 1
: :
num[99] = 99
numNums = 100
Затем, когда вы хотите случайное число, используйте следующий метод:
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.
Это вернет случайное значение из постоянно уменьшающегося пула, гарантируя отсутствие повторов. Вам, конечно, придется остерегаться того, что пул работает до нулевого размера, и разумно переинициализировать пул.
Это более детерминированное решение, чем сохранение списка используемых номеров и продолжение цикла, пока вы не найдете его в этом списке. Производительность такого алгоритма будет ухудшаться по мере уменьшения пула.
Функция C, использующая статические значения, примерно такая, должна сработать. Звони с
int i = myRandom (200);
для установки пула (с любым числом от нуля или больше, определяющим размер) или
int i = myRandom (-1);
чтобы получить следующий номер из пула (достаточно любого отрицательного числа). Если функция не может выделить достаточно памяти, она вернет -2. Если в пуле не осталось чисел, он вернет -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
Имейте в виду, что, поскольку в нем используется статика, звонить из двух разных мест небезопасно, если они хотят поддерживать свои собственные отдельные пулы. Если бы это было так, статика была бы заменена буфером (счетчик хранения и пул), который бы "принадлежал" вызывающей стороне (для этой цели можно было бы передать двойной указатель).
И, если вы ищете версию с несколькими пулами, я включу ее здесь для полноты.
#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()
, вам нужно сначала инициализировать указатель int
на NULL
, а затем передать его адрес функции myRandom()
. Это позволяет каждому клиенту (расположение в коде) иметь свой собственный пул, который автоматически выделяется и освобождается, хотя вы все равно можете совместно использовать пулы, если хотите.