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

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

См. также: A хороший список лучших практик

Я бы добавил, очень важно, хорошо использовать модификатор final. Использование "окончательной" модификатор, когда это применимо в Java

Сводка:

  1. Используйте модификатор final для обеспечения хорошей инициализации.
  2. Избегайте возврата null в методы, например, при возврате пустых коллекций.
  3. Использовать аннотации @NotNull и @Nullable
  4. Быстрое завершение работы и использование утверждений, чтобы избежать распространения нулевых объектов через все приложение, когда они не должен быть пустым.
  5. Сначала используйте значения с известным объектом: if("knownObject".equals(unknownObject)
  6. Предпочитают valueOf() поверх toString ().
  7. Используйте null safe StringUtils StringUtils.isEmpty(null).

174
задан Dukeling 16 July 2015 в 18:08
поделиться

10 ответов

Инициализируйте массив 1 001 целого числа со значениями 0-1000 и установите переменную, макс., к текущему макс. индексу массива (запускающийся с 1 000). Выберите случайное число, r, между 0 и макс., подкачайте число в положении r с числом в положении макс. и возвратите число теперь в положении, максимум Декрементном макс. 1, и продолжите. Когда макс. 0, устанавливает макс. назад на размер массива - 1 и запускаются снова без потребности повторно инициализировать массив.

Обновление: , Хотя я придумал этот метод самостоятельно, когда я ответил на вопрос после некоторого исследования, я понимаю, что это - измененная версия Фишер-Йетс известный как Durstenfeld-Fisher-Yates или Knuth-Fisher-Yates. Так как описанию может быть немного трудно следовать, я обеспечил пример ниже (использование 11 элементов вместо 1 001):

Массив начинается с 11 элементами, инициализированными для выстраивания [n] = n, макс. начинается в 10:

+--+--+--+--+--+--+--+--+--+--+--+
| 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|
+--+--+--+--+--+--+--+--+--+--+--+
                                ^
                               max    

При каждом повторении, случайное число r выбрано между 0 и макс., массив [r] и массив [макс.] подкачиваются, новый массив [макс.] возвращается, и макс. постепенно уменьшается:

max = 10, r = 3
           +--------------------+
           v                    v
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 1| 2|10| 4| 5| 6| 7| 8| 9| 3|
+--+--+--+--+--+--+--+--+--+--+--+

max = 9, r = 7
                       +-----+
                       v     v
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 1| 2|10| 4| 5| 6| 9| 8| 7: 3|
+--+--+--+--+--+--+--+--+--+--+--+

max = 8, r = 1
     +--------------------+
     v                    v
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 8| 2|10| 4| 5| 6| 9| 1: 7| 3|
+--+--+--+--+--+--+--+--+--+--+--+

max = 7, r = 5
                 +-----+
                 v     v
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 8| 2|10| 4| 9| 6| 5: 1| 7| 3|
+--+--+--+--+--+--+--+--+--+--+--+

...

После 11 повторений, все числа в массиве были выбраны, макс. == 0, и элементы массива переставляются:

+--+--+--+--+--+--+--+--+--+--+--+
| 4|10| 8| 6| 2| 0| 9| 5| 1| 7| 3|
+--+--+--+--+--+--+--+--+--+--+--+

На данном этапе макс. может быть сброшен к 10, и процесс может продолжиться.

239
ответ дан Green goblin 23 November 2019 в 20:29
поделиться

Другая возможность:

можно использовать массив флагов. И возьмите следующий когда это; s уже выбранный.

, Но, остерегайтесь после 1 000 вызовов функция никогда не будет заканчиваться так, необходимо сделать гарантию.

1
ответ дан Toon Krijthe 23 November 2019 в 20:29
поделиться

Вам даже не нужен массив для решения этого.

Вам нужны битовая маска и счетчик.

Инициализируют в противоречии с нулем и увеличивают его на последовательных вызовах. XOR счетчик с битовой маской (случайным образом выбранный при запуске или зафиксированный) для генерации psuedorandom числа. Если у Вас не может быть чисел, которые превышают 1000, не используйте битовую маску шире, чем 9 битов. (Другими словами, битовая маска является целым числом не выше 511.)

Удостоверяются, что, когда счетчик передает 1000, Вы обнуляете его. В это время можно выбрать другую случайную битовую маску — если Вам нравится — произвести тот же набор чисел в различном порядке.

5
ответ дан Max 23 November 2019 в 20:29
поделиться

Вы могли использовать Линейный Генератор Congruential . Где m (модуль) было бы самое близкое начало, больше, чем 1 000. Когда Вы вытаскиваете число из диапазона, просто получаете следующий. Последовательность только повторится, как только все элементы произошли, и Вы не должны использовать таблицу. Знайте о недостатках этого генератора хотя (включая отсутствие случайности).

21
ответ дан Paul de Vrieze 23 November 2019 в 20:29
поделиться

Используйте Максимальный Линейный Сдвиговый регистр .

Обратной связи, Это реализуемо в нескольких строках C, и во времени выполнения делает немного больше чем пару теста/ответвлений, небольшого дополнения и разрядного смещения. Это не случайно, но это дурачит большинство людей.

60
ответ дан plinth 23 November 2019 в 20:29
поделиться

Можно сделать это:

  1. Создают список, 0.. 1000.
  2. Перестановка список. (См. перестановка Фишера-Йетса для хорошего способа сделать это.)
  3. числа Возврата в порядке от переставленного списка.

, Таким образом, это не требует поиска старых значений каждый раз, но он все еще требует O (N) для начальной перестановки. Но поскольку Nils указал в комментариях, это амортизируется O (1).

71
ответ дан Chris Jester-Young 23 November 2019 в 20:29
поделиться

Вы могли использовать пользу генератор псевдослучайного числа с 10 битами и выбросить 1 001 - 1023 отъезда от 0 до 1 000.

От здесь мы получаем дизайн для PRNG на 10 битов..

  • 10 битов, многочлен обратной связи x^10 + x^7 + 1 (период 1023)

  • используют LFSR Galois для получения быстрого кода

2
ответ дан pro 23 November 2019 в 20:29
поделиться

Кто-то отправил "случайные числа создания в Excel". Я использую этот идеал. Создайте структуру с 2 частями, str.index и str.ran; Поскольку 10 случайных чисел создают массив 10 структур. Установите str.index от 0 до 9 и str.ran к другому случайному числу.

for(i=0;i<10; ++i) {
      arr[i].index = i;
      arr[i].ran   = rand();
}

Сортируют массив на значениях в прибытии [я] .ran. str.index находится теперь в произвольном порядке. Ниже код c:

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

struct RanStr { int index; int ran;};
struct RanStr arr[10];

int sort_function(const void *a, const void *b);

int main(int argc, char *argv[])
{
   int cnt, i;

   //seed(125);

   for(i=0;i<10; ++i)
   {
      arr[i].ran   = rand();
      arr[i].index = i;
      printf("arr[%d] Initial Order=%2d, random=%d\n", i, arr[i].index, arr[i].ran);
   }

   qsort( (void *)arr, 10, sizeof(arr[0]), sort_function);
   printf("\n===================\n");
   for(i=0;i<10; ++i)
   {
      printf("arr[%d] Random  Order=%2d, random=%d\n", i, arr[i].index, arr[i].ran);
   }

   return 0;
}

int sort_function(const void *a, const void *b)
{
   struct RanStr *a1, *b1;

   a1=(struct RanStr *) a;
   b1=(struct RanStr *) b;

   return( a1->ran - b1->ran );
}
-1
ответ дан 23 November 2019 в 20:29
поделиться

Для малых чисел, таких как 0 ... 1000, создание списка, содержащего все числа, и его перетасовка очень просто. Но если набор чисел для извлечения очень велик, есть еще один элегантный способ: вы можете построить псевдослучайную перестановку, используя ключ и криптографическую хеш-функцию. См. Следующий пример псевдокода C ++:

unsigned randperm(string key, unsigned bits, unsigned index) {
  unsigned half1 =  bits    / 2;
  unsigned half2 = (bits+1) / 2;
  unsigned mask1 = (1 << half1) - 1;
  unsigned mask2 = (1 << half2) - 1;
  for (int round=0; round<5; ++round) {
    unsigned temp = (index >> half1);
    temp = (temp << 4) + round;
    index ^= hash( key + "/" + int2str(temp) ) & mask1;
    index = ((index & mask2) << half1) | ((index >> half2) & mask1);
  }
  return index;
}

Здесь hash - это просто произвольная псевдослучайная функция, которая отображает строку символов в возможно огромное целое число без знака. Функция randperm представляет собой перестановку всех чисел в пределах 0 ... pow (2, bits) -1, предполагая фиксированный ключ. Это следует из конструкции, поскольку каждый шаг, изменяющий переменную index , является обратимым. Это навеяно шифром Фейстеля .

7
ответ дан 23 November 2019 в 20:29
поделиться

Вот код, который я набрал, использует логику первого решения. Я знаю, что это «независимо от языка», но просто хотел представить это в качестве примера на С# на случай, если кто-то ищет быстрое практическое решение.

// Initialize variables
Random RandomClass = new Random();
int RandArrayNum;
int MaxNumber = 10;
int LastNumInArray;
int PickedNumInArray;
int[] OrderedArray = new int[MaxNumber];      // Ordered Array - set
int[] ShuffledArray = new int[MaxNumber];     // Shuffled Array - not set

// Populate the Ordered Array
for (int i = 0; i < MaxNumber; i++)                  
{
    OrderedArray[i] = i;
    listBox1.Items.Add(OrderedArray[i]);
}

// Execute the Shuffle                
for (int i = MaxNumber - 1; i > 0; i--)
{
    RandArrayNum = RandomClass.Next(i + 1);         // Save random #
    ShuffledArray[i] = OrderedArray[RandArrayNum];  // Populting the array in reverse
    LastNumInArray = OrderedArray[i];               // Save Last Number in Test array
    PickedNumInArray = OrderedArray[RandArrayNum];  // Save Picked Random #
    OrderedArray[i] = PickedNumInArray;             // The number is now moved to the back end
    OrderedArray[RandArrayNum] = LastNumInArray;    // The picked number is moved into position
}

for (int i = 0; i < MaxNumber; i++)                  
{
    listBox2.Items.Add(ShuffledArray[i]);
}
3
ответ дан 23 November 2019 в 20:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: