Создать последовательность случайных чисел без повторений

Duplicate:

Уникальные случайные числа в O (1)?

Мне нужен генератор псевдослучайных чисел, который может генерировать числа без повторов в случайном порядке.

Например:

случайное (10)

может вернуться 5, 9, 1, 4, 2, 8, 3, 7, 6, 10

Есть ли лучший способ сделать это, кроме как сделать диапазон чисел и перетасовать их, или проверить сгенерированный список для повторений?


Edit:

Также я хочу, чтобы он был эффективен при создании больших чисел без всего диапазона.


Edit:

Я вижу, что все предлагают алгоритмы перетасовки. Но если я хочу генерировать большое случайное число (1024 байта +), то этот метод будет потреблять гораздо больше памяти, чем если бы я просто использовал обычный RNG и вставил в Set до тех пор, пока он не был заданной длиной, не так ли? Для этого нет лучшего математического алгоритма.

Ответ 1

Вас может заинтересовать линейный сдвиговый регистр обратной связи. Мы использовали их для сборки, но я также сделал их в программном обеспечении. Он использует регистр сдвига с некоторыми битами xor'ed и подает обратно на вход, и если вы выбираете только правильные "краны", вы можете получить последовательность, которая до тех пор, пока размер регистра. То есть 16-разрядный lfsr может генерировать последовательность 65535 длиной без повторов. Он статистически случайный, но, конечно, в высшей степени повторяемый. Кроме того, если это было сделано неправильно, вы можете получить некоторые смущающие короткие последовательности. Если вы посмотрите на lfsr, вы найдете примеры того, как их правильно построить (то есть "максимальная длина" ).

Ответ 2

Перетасовка - отличный способ сделать это (при условии, что вы не вводите предвзятость, используя наивный алгоритм). См. Fisher-Yates shuffle.

Ответ 3

Чтобы убедиться, что список не повторяется, ему нужно будет сохранить список ранее возвращенных чисел. Так как он должен генерировать весь список по окончании алгоритма, это эквивалентно требованию к хранению для создания упорядоченного списка и затем перетасовки.

Подробнее о перетасовке здесь: Создание случайного упорядоченного списка из упорядоченного списка

Однако, если диапазон случайных чисел очень велик, но количество требуемых чисел невелико (вы намекнули, что это фактическое требование в комментарии), затем сгенерируйте полный список и перетасовывая его, это расточительно. Перетасовка на огромном массиве предполагает доступ к страницам виртуальной памяти таким образом, что (по определению) победит систему подкачки ОС (в меньшем масштабе такая же проблема будет возникать в кэше памяти ЦП).

В этом случае поиск в списке до сих пор будет намного более эффективным. Поэтому идеальным было бы использовать эвристику (определенную экспериментом), чтобы выбрать правильную реализацию для данных аргументов. (Извинения за предоставление примеров в С#, а не С++, но ASFAС++ B Я тренирую себя, чтобы думать на С#).

IEnumerable<int> GenerateRandomNumbers(int range, int quantity)
{
    int[] a = new int[quantity];

    if (range < Threshold)
    {
        for (int n = 0; n < range; n++)
            a[n] = n;

        Shuffle(a);
    }
    else
    {
        HashSet<int> used = new HashSet<int>();

        for (int n = 0; n < quantity; n++)
        {
            int r = Random(range);

             while (!used.Add(r))
                 r = Random(range);

             a[n] = r;
        }
    }

    return a;
}

Стоимость выполнения повторных номеров, цикл при столкновении и т.д. будет дорогостоящим, но, вероятно, будет некоторое значение Threshold, где он будет быстрее, чем выделение для всего диапазона.

При достаточно малых требованиях к количеству может быть быстрее использовать массив для used и выполнять линейные поиски в нем из-за большей локальности, более низких издержек, дешевизны сравнения...

Также для больших величин AND больших диапазонов может быть предпочтительнее возвращать объект, который производит числа в последовательности по запросу, вместо выделения массива для результатов вверх. Это очень легко реализовать на С# благодаря ключевому слову yield return:

IEnumerable<int> ForLargeQuantityAndRange(int quantity, int range)
{
    for (int n = 0; n < quantity; n++)
    {
        int r = Random(range);

        while (!used.Add(r))
            r = Random(range);

        yield return r;
    }
}

Ответ 4

Если случайное число гарантировано никогда не повторяется, оно перестает быть случайным и количество случайности уменьшается с ростом числа (после того, как девять чисел random(10) являются довольно предсказуемыми и даже после восьми случаев у вас есть шанс 50-50).

Ответ 5

Я понимаю, что tou не хочет перетасовывать большие диапазоны, так как вам нужно будет сохранить весь список для этого.

Вместо этого используйте обратимый псевдослучайный хеш. Затем подайте в очередь значения 0 1 2 3 4 5 6 и т.д.

Здесь бесконечное количество хэшей. Их не так сложно создать, если они ограничены мощностью 2, но можно использовать любую базу.

Здесь один, который работал бы, например, если бы вы хотели пройти все 32-битные значения 2 ^ 32. Это проще всего написать, потому что неявный mod 2 ^ 32 целочисленной математики в этом случае работает в ваших интересах.

unsigned int reversableHash(unsigned int x)
{
   x*=0xDEADBEEF;
   x=x^(x>>17);
   x*=0x01234567;
   x+=0x88776655;
   x=x^(x>>4);
   x=x^(x>>9);
   x*=0x91827363;
   x=x^(x>>7);
   x=x^(x>>11);
   x=x^(x>>20);
   x*=0x77773333;
   return x;
}

Ответ 6

Перетасовка - это лучшее, что вы можете сделать для случайных чисел в определенном диапазоне без повторов. Причина, по которой метод, который вы описываете (произвольно генерируете числа и помещаете их в Set, пока не достигнете указанной длины), менее эффективен из-за дубликатов. Теоретически этот алгоритм никогда не завершится. В лучшем случае это закончится в неопределенное время, по сравнению с тасованием, которое всегда будет работать в очень предсказуемое время.

<ч/" > Ответ на изменения и комментарии:

Если, как вы укажете в комментариях, диапазон чисел очень велик, и вы хотите выбрать относительно немного из них наугад без повторов, тогда вероятность повторов быстро уменьшается. Чем больше разница в размере между диапазоном и количеством выборов, тем меньше вероятность повторных выборов, и тем лучше производительность будет для алгоритма выбора и проверки, который вы описываете в вопросе.

Ответ 8

Как насчет использования генератора GUID (например, в .NET). Конечно, не гарантируется, что дубликатов не будет, однако шанс получить один из них довольно низкий.

Ответ 9

Это было задано раньше - см. мой ответ на предыдущий вопрос. Вкратце: вы можете использовать блочный шифр для создания безопасной (случайной) перестановки в любом диапазоне, который вам нужен, без необходимости хранить всю перестановку в любой точке.

Ответ 10

Если вы хотите создать большие (скажем, 64 бит или более) случайные числа без повторов, тогда просто создайте их. Если вы используете хороший генератор случайных чисел, на самом деле достаточно энтропии, то вероятность генерации повторов настолько незначительна, что не стоит беспокоиться.

Например, при генерации криптографических ключей никто на самом деле не пытается проверить, не сгенерировал ли тот же ключ раньше; так как вы доверяете своему генератору случайных чисел, что выделенный злоумышленник не сможет получить один и тот же ключ, тогда почему вы ожидаете, что случайно придумаете один и тот же ключ?

Конечно, если у вас есть генератор случайных чисел (например, уязвимость генератора случайных чисел Debian) или генерируют достаточно мало цифры, которые парадоксальный день рождения дает вам высокую вероятность столкновения, тогда вам нужно будет что-то сделать, чтобы убедиться, что вы не получите повторений. Но для больших случайных чисел с хорошим генератором просто вероятность доверия не дать вам повторений.

Ответ 11

Когда вы создаете свои номера, используйте Bloom filter для обнаружения дубликатов. Это будет использовать минимальный объем памяти. Не было бы необходимости хранить ранние номера в серии вообще.

Компромисс заключается в том, что ваш список не может быть исчерпывающим в вашем диапазоне. Если ваши номера действительно имеют порядок 256 ^ 1024, это вряд ли вообще будет торговаться.

(Конечно, если они на самом деле случайны в этом масштабе, даже затруднять обнаружение дубликатов - это пустая трата времени. Если каждый компьютер на Земле генерировал триллион случайных чисел, размер которых каждую секунду за триллионы лет, вероятность столкновения по-прежнему абсолютно ничтожно.)

Ответ 12

Второй ответ gbarry об использовании LFSR. Они очень эффективны и просты в реализации даже в программном обеспечении и гарантированно не повторяются в (2 ^ N - 1) для LFSR с N-разрядным сдвиговым регистром.

Однако есть некоторые недостатки: наблюдая небольшое количество выходов из RNG, можно восстановить LFSR и предсказать все значения, которые он будет генерировать, что делает их непригодными для криптографии, и в любом месте нужен хороший RNG. Вторая проблема заключается в том, что либо полное нулевое слово, либо все (в терминах битов) слово недействительно в зависимости от реализации LFSR. Третий вопрос, который имеет отношение к вашему вопросу, заключается в том, что максимальное число, генерируемое LFSR, всегда имеет мощность 2 - 1 (или мощность 2 - 2).

Первый недостаток может не быть проблемой в зависимости от вашего приложения. Из примера, который вы дали, кажется, что вы не ожидаете, что ноль будет среди ответов; поэтому второй вопрос не имеет отношения к вашему делу. Проблема максимального значения (и, следовательно, диапазона) может быть решена путем повторного использования LFSR, пока вы не получите число в пределах вашего диапазона. Вот пример:

Предположим, вы хотите иметь номера от 1 до 10 (как в вашем примере). Вы бы использовали 4-битный LFSR, который имеет диапазон [1, 15] включительно. Здесь псевдо-код о том, как получить номер в диапазоне [1,10]:

x = LFSR.getRandomNumber();
while (x > 10) {
   x = LFSR.getRandomNumber();
}

Вы должны вставить предыдущий код в свой RNG; так что вызывающая сторона не заботится о реализации. Обратите внимание, что это замедлит ваш RNG, если вы используете большой регистр сдвига и максимальное количество, которое вы хотите, не имеет значения 2 - 1.

Ответ 13

Перемешивание элементов N не требует чрезмерной памяти... подумайте об этом. Вы заменяете только один элемент за раз, поэтому максимальная используемая память используется для N + 1 элементов.

Ответ 14

Предполагая, что у вас есть генератор случайных или псевдослучайных чисел, даже если он не гарантированно возвращает уникальные значения, вы можете реализовать тот, который каждый раз возвращает уникальные значения при использовании этого кода, предполагая, что верхний предел остается постоянным (т.е. вы всегда вызовите его с помощью random(10) и не вызывайте его с помощью random(10); random(11).

Код не проверяет наличие ошибок. Вы можете добавить это сами, если хотите.
Это также требует большой памяти, если вы хотите большой диапазон чисел.

/* the function returns a random number between 0 and max -1
 * not necessarily unique
 * I assume it written
 */
int random(int max);

/* the function returns a unique random number between 0 and max - 1 */
int unique_random(int max)
{

    static int *list = NULL;    /* contains a list of numbers we haven't returned */
    static int in_progress = 0; /* 0 --> we haven't started randomizing numbers
                                 * 1 --> we have started randomizing numbers
                                 */

    static int count;
    static prev_max = 0;

    // initialize the list
    if (!in_progress || (prev_max != max)) {
        if (list != NULL) {
            free(list);
        }
        list = malloc(sizeof(int) * max);
        prev_max = max;
        in_progress = 1;
        count = max - 1;

        int i;
        for (i = max - 1; i >= 0; --i) {
            list[i] = i;
        }
    }

    /* now choose one from the list */
    int index = random(count);
    int retval = list[index];

    /* now we throw away the returned value.
     * we do this by shortening the list by 1
     * and replacing the element we returned with
     * the highest remaining number
     */
    swap(&list[index], &list[count]);

    /* when the count reaches 0 we start over */
    if (count == 0) {
        in_progress = 0;
        free(list);
        list = 0;
    } else { /* reduce the counter by 1 */
        count--;
    }
}

/* swap two numbers */
void swap(int *x, int *y)
{
    int temp = *x;
    *x = *y;
    *y = temp;
}

Ответ 15

Предположим, вы хотели создать серию из 256 случайных чисел без повторений.

  • Создайте 256-битный (32-байтовый) блок памяти, инициализированный нулями, позвоните ему b
  • Ваша переменная цикла будет n, количество номеров, которые еще не сгенерированы
  • Цикл от n = 256 до n = 1
  • Создайте случайное число r в диапазоне [0, n)
  • Найдите r -ный нулевой бит в блоке памяти b, позвоните ему p
  • Поместите p в список результатов, массив с именем q
  • Переверните p -ый бит в блоке памяти b в 1
  • После прохода n = 1 вы закончили генерировать свой список чисел

Вот краткий пример того, о чем я говорю, используя n= 4 изначально:

**Setup**
b = 0000
q = []

**First loop pass, where n = 4**
r = 2
p = 2
b = 0010
q = [2]

**Second loop pass, where n = 3**
r = 2
p = 3
b = 0011
q = [2, 3]

**Third loop pass, where n = 2**
r = 0
p = 0
b = 1011
q = [2, 3, 0]

** Fourth and final loop pass, where n = 1**
r = 0
p = 1
b = 1111
q = [2, 3, 0, 1]

Ответ 18

static std::unordered_set<long> s;
long l = 0;
for(; !l && (s.end() != s.find(l)); l = generator());
v.insert(l);

generator() - ваш генератор случайных чисел. Вы переворачиваете числа до тех пор, пока запись не находится в вашем наборе, тогда вы добавляете то, что находите в ней. Вы поняли эту идею.

Я сделал это с длинными примерами, но вы должны сделать этот шаблон, если ваш PRNG будет templatized.

Альтернативой является использование криптографически защищенного PRNG, который будет иметь очень низкую вероятность генерировать вдвое большее число.

Ответ 19

Если вы не имеете в виду плохие статистические свойства сгенерированной последовательности, существует один метод:

Предположим, вы хотите сгенерировать N чисел, каждый из 1024 бит каждый. Вы можете пожертвовать некоторыми битами сгенерированного числа как "счетчик".

Итак, вы генерируете каждое случайное число, но в некоторые биты, которые вы выбрали, вы помещаете двоичный закодированный счетчик (из переменной вы увеличиваете каждый раз, когда генерируется следующий случайный номер).

Вы можете разбить это число на отдельные биты и поместить его в несколько менее значимых бит сгенерированного числа.

Таким образом, вы уверены, что каждый раз получаете уникальный номер.

Я имею в виду, например, каждое сгенерированное число выглядит следующим образом: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyxxxxyxyyyyxxyxx где x берется непосредственно из генератора, а ys берутся из переменной счетчика.

Ответ 20

Мерсенн твистер

Описание которого можно найти здесь, в Википедии: Mersenne twister

Посмотрите на нижнюю часть страницы для реализаций на разных языках.

Ответ 21

Задача состоит в том, чтобы выбрать "случайную" последовательность из N уникальных чисел из диапазона 1..M, где нет ограничения на связь между N и M (M может быть намного больше, примерно одинаково или даже меньше чем N, они не могут быть взаимно простыми).

Развертывание в регистре сдвига с линейной обратной связью: для данного M постройте максимальную LFSR для наименьшей мощности двух, которая больше M. Затем просто хватайте свои номера из LFSR, выкидывая числа, большие, чем M. В среднем, вы выбрасываете максимум половину сгенерированных чисел (так как при построении более половины диапазона LFSR меньше М), поэтому ожидаемое время работы для получения числа равно O (1). Вы не сохраняете ранее сгенерированные числа, поэтому потребление пространства равно O (1). Если вы зацикливаете до получения N чисел, то M меньше N (или LFSR создается неправильно).

Здесь вы можете найти параметры для максимальной длины LFSR до 168 бит (из wikipedia): http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf

Вот код java:

/**  * Создайте последовательность уникальных "случайных" чисел в [0, M)  * @author dkoes  *  */

открытый класс UniqueRandom {   long lfsr;   длинная маска;   long max;

private static long seed = 1;
//indexed by number of bits
private static int [][] taps = {
        null, // 0
        null, // 1
        null, // 2
        {3,2}, //3
        {4,3},
        {5,3},
        {6,5},
        {7,6},
        {8,6,5,4},
        {9,5},
        {10,7},
        {11,9},
        {12,6,4,1},
        {13,4,3,1},
        {14,5,3,1},
        {15,14},
        {16,15,13,4},
        {17,14},
        {18,11},
        {19,6,2,1},
        {20,17},
        {21,19},
        {22,21},
        {23,18},
        {24,23,22,17},
        {25,22},
        {26,6,2,1},
        {27,5,2,1},
        {28,25},
        {29,27},
        {30,6,4,1},
        {31,28},
        {32,22,2,1},
        {33,20},
        {34,27,2,1},
        {35,33},
        {36,25},
        {37,5,4,3,2,1},
        {38,6,5,1},
        {39,35},
        {40,38,21,19},
        {41,38},
        {42,41,20,19},
        {43,42,38,37},
        {44,43,18,17},
        {45,44,42,41},
        {46,45,26,25},
        {47,42},
        {48,47,21,20},
        {49,40},
        {50,49,24,23},
        {51,50,36,35},
        {52,49},
        {53,52,38,37},
        {54,53,18,17},
        {55,31},
        {56,55,35,34},
        {57,50},
        {58,39},
        {59,58,38,37},
        {60,59},
        {61,60,46,45},
        {62,61,6,5},
        {63,62},
};

//m is upperbound; things break if it isn't positive
UniqueRandom(long m)
{
    max = m;
    lfsr = seed; //could easily pass a starting point instead
    //figure out number of bits
    int bits = 0;
    long b = m;
    while((b >>>= 1) != 0)
    {
        bits++;
    }
    bits++;

    if(bits < 3)
        bits = 3; 

    mask = 0;
    for(int i = 0; i < taps[bits].length; i++)
    {
        mask |= (1L << (taps[bits][i]-1));
    }

}

//return -1 if we've cycled
long next()
{
    long ret = -1;
    if(lfsr == 0)
        return -1;
    do {
        ret = lfsr;
        //update lfsr - from wikipedia
        long lsb = lfsr & 1;
        lfsr >>>= 1;
        if(lsb == 1)
            lfsr ^= mask;

        if(lfsr == seed)            
            lfsr = 0; //cycled, stick

        ret--; //zero is stuck state, never generated so sub 1 to get it
    } while(ret >= max);

    return ret;
}

}

Ответ 22

Этот ответ предлагает некоторые стратегии для получения того, что вы хотите, и обеспечения того, чтобы они находились в произвольном порядке с использованием некоторых уже известных алгоритмов.

Существует внутренняя версия алгоритма Shuffle Fisher-Yates, называемая версией Durstenfeld, которая случайным образом распределяет последовательно полученные предметы в массивы и коллекции при загрузке массива или коллекции.

Одна вещь, которую следует помнить, заключается в том, что Shuffle Fisher-Yates (AKA Knuth) или версия Durstenfeld, используемая во время загрузки, очень эффективны с массивами объектов, потому что перемещается только указатель ссылки на объект и сам объект не " t необходимо изучить или сравнить с любым другим объектом как частью алгоритма.

Я дам оба алгоритма ниже.

Если вам нужны действительно огромные случайные числа, порядка 1024 байт или более, достаточно хороший случайный генератор, который может генерировать неподписанные байты или слова за раз. Произвольно генерируйте столько байтов или слов, сколько вам нужно, чтобы построить число, превратите его в объект с указателем ссылки на него и, эй, престо, у вас действительно огромное случайное целое число. Если вам нужен конкретный действительно огромный диапазон, вы можете добавить базовое значение нулевых байтов в младший конец байтовой последовательности, чтобы сдвинуть значение вверх. Это может быть вашим лучшим вариантом.

Если вам нужно устранить дубликаты действительно огромных случайных чисел, то это сложнее. Даже при действительно огромных случайных числах удаление дубликатов также делает их значительно предвзятыми и не случайными вообще. Если у вас действительно большой набор неразмножаемых действительно огромных случайных чисел, и вы произвольно выбираете из тех, которые еще не выбраны, то смещение - это только смещение в создании огромных значений для действительно огромного набора чисел, из которого можно выбрать. Обратную версию версии Yates-Fisher Durstenfeld можно использовать для случайного выбора значений из действительно огромного набора из них, удалить их из оставшихся значений, из которых можно выбрать и вставить их в новый массив, который является подмножеством, и мог бы делать это только с исходными и целевыми массивами на месте. Это было бы очень эффективно.

Это может быть хорошей стратегией для получения небольшого числа случайных чисел с огромными значениями из действительно большого набора из них, в которых они не дублируются. Просто выберите случайное местоположение в исходном наборе, получите его значение, измените его значение с помощью верхнего элемента в исходном наборе, уменьшите размер источника, установленного на единицу, и повторите с уменьшенным источником размера, пока вы не выберете достаточное количество значений. Это важно, чтобы версия Дурстенфельда Fisher-Yates была обратная. Затем вы можете использовать версию алгоритма Fisher-Yates от Dursenfeld, чтобы вставить полученные значения в набор адресатов. Тем не менее, это перебор, поскольку они должны быть случайно выбраны и произвольно упорядочены, как указано здесь.

Оба алгоритма предполагают, что у вас есть метод случайного числа экземпляров, nextInt (int setSize), который генерирует случайное целое число от нуля до значения setSize, что есть допустимые значения setSize. В этом случае это будет размер массива, так как последним индексом для массива является размер-1.

Первый алгоритм - это алгоритм Shuffle алгоритма Fisher-Yates (aka Knuth), используемый в Durstenfeld, применительно к массиву произвольной длины, который просто случайным образом позиционирует целые числа от 0 до длины массива в массив. Массив не должен быть массивом целых чисел, но может быть массивом любых объектов, которые приобретаются последовательно, что, фактически, делает его массивом опорных указателей. Это просто, коротко и очень эффективно

int size = someNumber;
int[] int array = new int[size]; // here is the array to load
int location; // this will get assigned a value before used
// i will also conveniently be the value to load, but any sequentially acquired
// object will work
for (int i = 0; i <= size; i++) { // conveniently, i is also the value to load
      // you can instance or acquire any object at this place in the algorithm to load
      // by reference, into the array and use a pointer to it in place of j
      int j = i; // in this example, j is trivially i
    if (i == 0) { // first integer goes into first location
        array[i] = j; // this may get swapped from here later
    } else { // subsequent integers go into random locations
            // the next random location will be somewhere in the locations
            // already used or a new one at the end
            // here we get the next random location
            // to preserve true randomness without a significant bias
            // it is REALLY IMPORTANT that the newest value could be
            // stored in the newest location, that is, 
            // location has to be able to randomly have the value i
            int location = nextInt(i + 1); // a random value between 0 and i
            // move the random location value to the new location
            array[i] = array[location];
            array[location] = j; // put the new value into the random location
    } // end if...else
} // end for

Voila, теперь у вас уже рандомизированный массив.

Если вы хотите случайным образом перетасовать массив, который у вас уже есть, вот стандартный алгоритм Фишера-Йейса.

type[] array = new type[size];

// some code that loads array...

// randomly pick an item anywhere in the current array segment, 
// swap it with the top element in the current array segment,
// then shorten the array segment by 1
// just as with the Durstenfeld version above,
// it is REALLY IMPORTANT that an element could get
// swapped with itself to avoid any bias in the randomization
type temp; // this will get assigned a value before used
int location; // this will get assigned a value before used
for (int i = arrayLength -1 ; i > 0; i--) {
    int location = nextInt(i + 1);
    temp = array[i];
    array[i] = array[location];
    array[location] = temp;
} // end for

Для секвенированных коллекций и наборов, то есть какого-либо типа объекта списка, вы можете просто использовать добавление/или вставки с индексом, которое позволяет вставлять элементы в любом месте, но оно должно разрешать добавление или добавление после текущего последнего элемента в избегать создания смещения в рандомизации.

Ответ 23

Вот способ случайности без повторения результатов. Он также работает для строк. Его в С#, но logig должен работать во многих местах. Поместите случайные результаты в список и проверьте, есть ли новый случайный элемент в этом списке. Если нет, то у вас есть новый случайный элемент. Если он находится в этом списке, повторите случайное, пока не получите элемент, который не находится в этом списке.

List<string> Erledigte = new List<string>();
private void Form1_Load(object sender, EventArgs e)
{
    label1.Text = "";
    listBox1.Items.Add("a");
    listBox1.Items.Add("b");
    listBox1.Items.Add("c");
    listBox1.Items.Add("d");
    listBox1.Items.Add("e");
}

private void button1_Click(object sender, EventArgs e)
{
    Random rand = new Random();
    int index=rand.Next(0, listBox1.Items.Count);
    string rndString = listBox1.Items[index].ToString();

    if (listBox1.Items.Count <= Erledigte.Count)
    {
        return;
    }
    else
    {
        if (Erledigte.Contains(rndString))
        {
            //MessageBox.Show("vorhanden");
            while (Erledigte.Contains(rndString))
            {
                index = rand.Next(0, listBox1.Items.Count);
                rndString = listBox1.Items[index].ToString();
            }
        }

        Erledigte.Add(rndString);
        label1.Text += rndString;
    }
}

Ответ 24

Для последовательности, которая должна быть случайной, не должно быть никакой автоматической корреляции. Ограничение, которое номера не должны повторять, означает, что следующее число должно зависеть от всех предыдущих чисел, что означает, что оно не является случайным.

Ответ 25

Если вы можете генерировать "маленькие" случайные числа, вы можете генерировать "большие" случайные числа, интегрируя их: добавьте небольшое случайное приращение к каждому "предыдущему".

const size_t amount = 100; // a limited amount of random numbers
vector<long int> numbers; 
numbers.reserve( amount );
const short int spread = 250; // about 250 between each random number
numbers.push_back( myrandom( spread ) );
for( int n = 0; n != amount; ++n ) {
    const short int increment = myrandom( spread );
    numbers.push_back( numbers.back() + increment );
}

myshuffle( numbers );

Функции myrandom и myshuffle, которые я щедро передаю другим:)

Ответ 26

Собственно, здесь есть небольшой момент; генератор случайных чисел, который не разрешается повторять, не является случайным.

Ответ 27

иметь не повторяющиеся случайные числа и избегать времени ожидания с проверкой чисел удвоений и снова использовать новые числа, используя приведенный ниже метод, который обеспечит минимальное использование Rand: например, если вы хотите получить 100 неперечисленных случайных чисел: 1. заполнить массив номерами от 1 до 100 2. получить случайное число, используя функцию Rand в диапазоне (1-100) 3. используйте случайное число genarted как индекс для получения значения из массива (Numbers [IndexGeneratedFromRandFunction] 4. сдвиньте число в массиве после этого индекса влево 5. повторите шаг 2, но теперь зазвон должен быть (1-99) и продолжать

Ответ 28

теперь у нас есть массив с разными номерами!

int main() {
    int b[(the number
    if them)];
    for (int i = 0; i < (the number of them); i++) {
    int a = rand() % (the number of them + 1) + 1;
    int j = 0;
    while (j < i) {
        if (a == b[j]) {
        a = rand() % (the number of them + 1) + 1;
        j = -1;
        }
        j++;
    }
    b[i] = a;
    }
}