Подтвердить что ты не робот

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

В этом случае MAX составляет всего 5, поэтому я могу проверять дубликаты один за другим, но как я мог сделать это проще? Например, что, если MAX имеет значение 20? Спасибо.

int MAX = 5;

for (i = 1 , i <= MAX; i++)
{
        drawNum[1] = (int)(Math.random()*MAX)+1;

        while (drawNum[2] == drawNum[1])
        {
             drawNum[2] = (int)(Math.random()*MAX)+1;
        }
        while ((drawNum[3] == drawNum[1]) || (drawNum[3] == drawNum[2]) )
        {
             drawNum[3] = (int)(Math.random()*MAX)+1;
        }
        while ((drawNum[4] == drawNum[1]) || (drawNum[4] == drawNum[2]) || (drawNum[4] == drawNum[3]) )
        {
             drawNum[4] = (int)(Math.random()*MAX)+1;
        }
        while ((drawNum[5] == drawNum[1]) ||
               (drawNum[5] == drawNum[2]) ||
               (drawNum[5] == drawNum[3]) ||
               (drawNum[5] == drawNum[4]) )
        {
             drawNum[5] = (int)(Math.random()*MAX)+1;
        }

}
4b9b3361

Ответ 1

Самый простой способ - создать список возможных чисел (1..20 или что-то еще), а затем перетасовать их с помощью Collections.shuffle. Тогда просто возьмите все, что захотите. Это здорово, если ваш диапазон равен количеству элементов, которые вам нужны в конце (например, для перетасовки колоды карт).

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

if (max < numbersNeeded)
{
    throw new IllegalArgumentException("Can't ask for more numbers than are available");
}
Random rng = new Random(); // Ideally just create one instance globally
// Note: use LinkedHashSet to maintain insertion order
Set<Integer> generated = new LinkedHashSet<Integer>();
while (generated.size() < numbersNeeded)
{
    Integer next = rng.nextInt(max) + 1;
    // As we're adding to a set, this will automatically do a containment check
    generated.add(next);
}

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

Еще один вариант - всегда добиваться прогресса, уменьшая диапазон каждый раз и компенсируя существующие значения. Например, предположим, что вам нужно 3 значения в диапазоне 0..9. На первой итерации вы должны сгенерировать любое число в диапазоне 0..9 - допустим, вы создаете 4.

На второй итерации вы должны сгенерировать число в диапазоне 0..8. Если сгенерированное число меньше 4, вы сохраните его как есть... иначе вы добавите его в него. Это дает вам диапазон результатов от 0..9 без 4. Предположим, что мы получаем 7.

На третьей итерации вы должны сгенерировать число в диапазоне 0..7. Если сгенерированное число меньше 4, вы сохраните его как есть. Если это 4 или 5, вы должны добавить один. Если это 6 или 7, вы бы добавили два. Таким образом, диапазон результатов равен 0..9 без 4 или 6.

Ответ 2

Вот как бы я это сделал

import java.util.ArrayList;
import java.util.Random;

public class Test {
    public static void main(String[] args) {
        int size = 20;

        ArrayList<Integer> list = new ArrayList<Integer>(size);
        for(int i = 1; i <= size; i++) {
            list.add(i);
        }

        Random rand = new Random();
        while(list.size() > 0) {
            int index = rand.nextInt(list.size());
            System.out.println("Selected: "+list.remove(index));
        }
    }
}

Как уважаемый господин Скит указал:
Если n - количество случайно выбранных чисел, которые вы хотите выбрать, а N - общее пространство выборки доступных для выбора чисел:

  • Если n < N, вы должны просто сохранить числа, которые вы выбрали, и проверить список, чтобы узнать, находится ли в нем номер.
  • Если n ~ = N, вы, вероятно, должны использовать мой метод, заполнив список, содержащий все пространство выборки, а затем удалите из него номера по мере их выбора.

Ответ 3

//random numbers are 0,1,2,3 
ArrayList<Integer> numbers = new ArrayList<Integer>();   
Random randomGenerator = new Random();
while (numbers.size() < 4) {

    int random = randomGenerator .nextInt(4);
    if (!numbers.contains(random)) {
        numbers.add(random);
    }
}

Ответ 4

Существует еще один способ делать "случайные" упорядоченные числа с LFSR, взглянуть на:

http://en.wikipedia.org/wiki/Linear_feedback_shift_register

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

Но это не ИСТИННЫЕ случайные числа, потому что случайная генерация детерминирована.

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

Вот алгоритм LFSR в java, (я взял его где-то, я не помню):

public final class LFSR {
    private static final int M = 15;

    // hard-coded for 15-bits
    private static final int[] TAPS = {14, 15};

    private final boolean[] bits = new boolean[M + 1];

    public LFSR() {
        this((int)System.currentTimeMillis());
    }

    public LFSR(int seed) {
        for(int i = 0; i < M; i++) {
            bits[i] = (((1 << i) & seed) >>> i) == 1;
        }
    }

    /* generate a random int uniformly on the interval [-2^31 + 1, 2^31 - 1] */
    public short nextShort() {
        //printBits();

        // calculate the integer value from the registers
        short next = 0;
        for(int i = 0; i < M; i++) {
            next |= (bits[i] ? 1 : 0) << i;
        }

        // allow for zero without allowing for -2^31
        if (next < 0) next++;

        // calculate the last register from all the preceding
        bits[M] = false;
        for(int i = 0; i < TAPS.length; i++) {
            bits[M] ^= bits[M - TAPS[i]];
        }

        // shift all the registers
        for(int i = 0; i < M; i++) {
            bits[i] = bits[i + 1];
        }

        return next;
    }

    /** returns random double uniformly over [0, 1) */
    public double nextDouble() {
        return ((nextShort() / (Integer.MAX_VALUE + 1.0)) + 1.0) / 2.0;
    }

    /** returns random boolean */
    public boolean nextBoolean() {
        return nextShort() >= 0;
    }

    public void printBits() {
        System.out.print(bits[M] ? 1 : 0);
        System.out.print(" -> ");
        for(int i = M - 1; i >= 0; i--) {
            System.out.print(bits[i] ? 1 : 0);
        }
        System.out.println();
    }


    public static void main(String[] args) {
        LFSR rng = new LFSR();
        Vector<Short> vec = new Vector<Short>();
        for(int i = 0; i <= 32766; i++) {
            short next = rng.nextShort();
            // just testing/asserting to make 
            // sure the number doesn't repeat on a given list
            if (vec.contains(next))
                throw new RuntimeException("Index repeat: " + i);
            vec.add(next);
            System.out.println(next);
        }
    }
}

Ответ 5

Другой подход, который позволяет указать, сколько чисел вы хотите с size и min и max значения возвращаемых чисел

public static int getRandomInt(int min, int max) {
    Random random = new Random();

    return random.nextInt((max - min) + 1) + min;
}

public static ArrayList<Integer> getRandomNonRepeatingIntegers(int size, int min,
        int max) {
    ArrayList<Integer> numbers = new ArrayList<Integer>();

    while (numbers.size() < size) {
        int random = getRandomInt(min, max);

        if (!numbers.contains(random)) {
            numbers.add(random);
        }
    }

    return numbers;
}

Чтобы использовать его, возвращающее 7 чисел от 0 до 25.

    ArrayList<Integer> list = getRandomNonRepeatingIntegers(7, 0, 25);
    for (int i = 0; i < list.size(); i++) {
        System.out.println("" + list.get(i));
    }

Ответ 6

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

// get 5 unique random numbers, possible values 0 - 19
// (assume desired number of selections < number of choices)

const int POOL_SIZE = 20;
const int VAL_COUNT = 5;

declare Array mapping[POOL_SIZE];
declare Array results[VAL_COUNT];

declare i int;
declare r int;
declare max_rand int;

// create mapping array
for (i=0; i<POOL_SIZE; i++) {
   mapping[i] = i;
}

max_rand = POOL_SIZE-1;  // start loop searching for maximum value (19)

for (i=0; i<VAL_COUNT; i++) {
    r = Random(0, max_rand); // get random number
    results[i] = mapping[r]; // grab number from map array
    mapping[r] = max_rand;  // place item past range at selected location

    max_rand = max_rand - 1;  // reduce random scope by 1
}

Предположим, что первая итерация породила случайное число 3 (начиная с 0 - 19). Это дало бы результаты [0] = mapping [3], т.е. Значение 3. Тогда мы присвоили отображение [3] равным 19.

В следующей итерации случайное число составляло 5 (от 0 до 18). Это дало бы результаты [1] = mapping [5], т.е. Значение 5. Затем мы присвоили отображение [5] равным 18.

Теперь предположим, что следующая итерация снова выбрала 3 (от 0 до 17). результатам [2] присваивается значение отображения [3], но теперь это значение не равно 3, но 19.

Эта же защита сохраняется для всех номеров, даже если вы получили то же число 5 раз подряд. Например, если генератор случайных чисел дал вам 0 пять раз подряд, результаты будут следующими: [0, 19, 18, 17, 16].

Вы никогда не получите одинаковый номер дважды.

Ответ 7

Генерация всех индексов последовательности, как правило, является плохой идеей, так как это может занять много времени, особенно если отношение номеров, которые нужно выбрать к MAX, невелико (в сложности преобладает O(MAX)). Это ухудшается, если отношение числа, которое нужно выбрать к MAX, приближается к одному, так как затем удаление выбранных индексов из последовательности всех также становится дорогостоящим (мы приближаемся к O(MAX^2/2)). Но для небольших чисел это, как правило, хорошо работает и не особенно подвержено ошибкам.

Фильтрация сгенерированных индексов с использованием коллекции также является плохой идеей, так как некоторое время тратится на вставку индексов в последовательность, и прогресс не гарантируется, так как одно и то же случайное число можно рисовать несколько раз (но для достаточно больших MAX маловероятно). Это может быть близко к сложности O(k n log^2(n)/2), игнорируя дубликаты и предполагая, что коллекция использует дерево для эффективного поиска (но со значительной постоянной стоимостью k выделения узлов дерева и, возможно, для балансировка).

Другой вариант - генерировать случайные значения уникально с самого начала, гарантируя прогресс. Это означает, что в первом раунде генерируется случайный индекс в [0, MAX]:

items i0 i1 i2 i3 i4 i5 i6 (total 7 items)
idx 0       ^^             (index 2)

Во втором раунде генерируется только [0, MAX - 1] (поскольку один элемент уже выбран):

items i0 i1    i3 i4 i5 i6 (total 6 items)
idx 1          ^^          (index 2 out of these 6, but 3 out of the original 7)

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

Для коротких последовательностей это довольно быстрый алгоритм O(n^2/2):

void RandomUniqueSequence(std::vector<int> &rand_num,
    const size_t n_select_num, const size_t n_item_num)
{
    assert(n_select_num <= n_item_num);

    rand_num.clear(); // !!

    // b1: 3187.000 msec (the fastest)
    // b2: 3734.000 msec
    for(size_t i = 0; i < n_select_num; ++ i) {
        int n = n_Rand(n_item_num - i - 1);
        // get a random number

        size_t n_where = i;
        for(size_t j = 0; j < i; ++ j) {
            if(n + j < rand_num[j]) {
                n_where = j;
                break;
            }
        }
        // see where it should be inserted

        rand_num.insert(rand_num.begin() + n_where, 1, n + n_where);
        // insert it in the list, maintain a sorted sequence
    }
    // tier 1 - use comparison with offset instead of increment
}

Где n_select_num - ваш 5 и n_number_num - ваш MAX. n_Rand(x) возвращает случайные целые числа в [0, x] (включительно). Это можно сделать немного быстрее, если выбрать много элементов (например, не 5, а 500), используя двоичный поиск, чтобы найти точку вставки. Для этого нам необходимо убедиться, что мы отвечаем требованиям.

Мы будем выполнять бинарный поиск с помощью сравнения n + j < rand_num[j], который совпадает с n < rand_num[j] - j. Нам нужно показать, что rand_num[j] - j по-прежнему является упорядоченной последовательностью для упорядоченной последовательности rand_num[j]. Это, к счастью, легко показано, так как наименьшее расстояние между двумя элементами оригинала rand_num равно единице (порожденные числа уникальны, поэтому всегда существует разница не менее 1). В то же время, если мы вычитаем индексы j из всех элементов rand_num[j], различия в индексе равны 1. Таким образом, в "худшем" случае мы получаем постоянную последовательность, но никогда не уменьшаемся. Поэтому можно использовать двоичный поиск, приводящий к алгоритму O(n log(n)):

struct TNeedle { // in the comparison operator we need to make clear which argument is the needle and which is already in the list; we do that using the type system.
    int n;

    TNeedle(int _n)
        :n(_n)
    {}
};

class CCompareWithOffset { // custom comparison "n < rand_num[j] - j"
protected:
    std::vector<int>::iterator m_p_begin_it;

public:
    CCompareWithOffset(std::vector<int>::iterator p_begin_it)
        :m_p_begin_it(p_begin_it)
    {}

    bool operator ()(const int &r_value, TNeedle n) const
    {
        size_t n_index = &r_value - &*m_p_begin_it;
        // calculate index in the array

        return r_value < n.n + n_index; // or r_value - n_index < n.n
    }

    bool operator ()(TNeedle n, const int &r_value) const
    {
        size_t n_index = &r_value - &*m_p_begin_it;
        // calculate index in the array

        return n.n + n_index < r_value; // or n.n < r_value - n_index
    }
};

И наконец:

void RandomUniqueSequence(std::vector<int> &rand_num,
    const size_t n_select_num, const size_t n_item_num)
{
    assert(n_select_num <= n_item_num);

    rand_num.clear(); // !!

    // b1: 3578.000 msec
    // b2: 1703.000 msec (the fastest)
    for(size_t i = 0; i < n_select_num; ++ i) {
        int n = n_Rand(n_item_num - i - 1);
        // get a random number

        std::vector<int>::iterator p_where_it = std::upper_bound(rand_num.begin(), rand_num.end(),
            TNeedle(n), CCompareWithOffset(rand_num.begin()));
        // see where it should be inserted

        rand_num.insert(p_where_it, 1, n + p_where_it - rand_num.begin());
        // insert it in the list, maintain a sorted sequence
    }
    // tier 4 - use binary search
}

Я тестировал это по трем критериям. Во-первых, 3 номера были выбраны из 7 пунктов, и гистограмма выбранных предметов была накоплена за 10 000 прогонов:

4265 4229 4351 4267 4267 4364 4257

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

Второй тест включал выбор 7 номеров из 5000 предметов. Время выполнения нескольких версий алгоритма было накоплено за 10 000 000 пробегов. Результаты обозначаются в комментариях в коде как b1. Простая версия алгоритма немного быстрее.

В третьем эталоне участвовало 700 номеров из 5000 предметов. Время нескольких версий алгоритма снова накопилось, на этот раз более 10 000 запусков. Результаты обозначаются в комментариях в коде как b2. Бинарная версия поиска алгоритма теперь более чем в два раза быстрее, чем простая.

Второй способ начинается быстрее для выбора более чем на 75 позиций на моей машине (обратите внимание, что сложность любого алгоритма не зависит от количества элементов, MAX).

Стоит отметить, что приведенные выше алгоритмы генерируют случайные числа в порядке возрастания. Но было бы просто добавить еще один массив, в который числа будут сохранены в том порядке, в котором они были сгенерированы, и вместо этого вернется (при незначительной дополнительной стоимости O(n)). Нет необходимости перетасовывать вывод: это будет намного медленнее.

Обратите внимание, что источники находятся на С++, у меня нет Java на моей машине, но концепция должна быть ясной.

ИЗМЕНИТЬ

Для развлечения я также реализовал подход, который генерирует список со всеми индексами 0 .. MAX, выбирает их случайным образом и удаляет из списка, чтобы гарантировать уникальность. Поскольку я выбрал довольно высокий MAX (5000), производительность катастрофична:

// b1: 519515.000 msec
// b2: 20312.000 msec
std::vector<int> all_numbers(n_item_num);
std::iota(all_numbers.begin(), all_numbers.end(), 0);
// generate all the numbers

for(size_t i = 0; i < n_number_num; ++ i) {
    assert(all_numbers.size() == n_item_num - i);
    int n = n_Rand(n_item_num - i - 1);
    // get a random number

    rand_num.push_back(all_numbers[n]); // put it in the output list
    all_numbers.erase(all_numbers.begin() + n); // erase it from the input
}
// generate random numbers

Я также внедрил подход с set (С++-коллекцией), который на втором месте стоит в тесте b2, что примерно на 50% медленнее, чем подход с двоичным поиском. Это понятно, так как set использует двоичное дерево, где стоимость вставки похожа на двоичный поиск. Единственное различие - это шанс получить повторяющиеся предметы, что замедляет прогресс.

// b1: 20250.000 msec
// b2: 2296.000 msec
std::set<int> numbers;
while(numbers.size() < n_number_num)
    numbers.insert(n_Rand(n_item_num - 1)); // might have duplicates here
// generate unique random numbers

rand_num.resize(numbers.size());
std::copy(numbers.begin(), numbers.end(), rand_num.begin());
// copy the numbers from a set to a vector

Полный исходный код здесь.

Ответ 8

Это было бы намного проще в java-8:

Stream.generate(new Random()::ints)
            .distinct()
            .limit(16) // whatever limit you might need
            .toArray(Integer[]::new);

Ответ 9

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

Если возвращаемое значение равно false, вы знаете, что номер уже был создан раньше.

Ответ 10

Вместо того, чтобы делать все это, создайте объект LinkedHashSet и случайные числа для него функцией Math.random().... если какая-либо повторяющаяся запись происходит, объект LinkedHashSet не добавит это число в свой список... Поскольку в этом классе коллекции не допускаются повторяющиеся значения. В конце вы получите список случайных чисел, не имеющих дублирующихся значений....: D

Ответ 11

Кажется, ваша проблема сводится к выбору k элементов случайным образом из набора из n элементов. Таким образом, запрос Collections.shuffle является правильным, но, как указано, неэффективен: его O (n).

Википедия: Fisher-Yates shuffle имеет версию O (k), когда массив уже существует. В вашем случае нет массива элементов, и создание массива элементов может быть очень дорогостоящим, скажем, если max было 10000000 вместо 20.

Алгоритм тасования включает в себя инициализацию массива размера n, где каждый элемент равен его индексу, подбирая k случайных чисел каждое число в диапазоне с максимальным, меньшим, чем предыдущий диапазон, затем заменяя элементы на конец массива,

Вы можете сделать ту же операцию в O (k) время с помощью hashmap, хотя я признаю ее вид боли. Заметим, что это стоит того, если k намного меньше n. (т.е. k ~ lg (n) или так), в противном случае вы должны использовать тасование напрямую.

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

  • Выберите k случайных чисел: первый находится в диапазоне от 0 до n-1, второй от 0 до n-2, третий от 0 до n-3 и т.д., через n-k.

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

int getValue(i)
{
    if (map.contains(i)) 
        return map[i];
    return i;
}

void setValue(i, val)
{   
    if (i == val)
        map.remove(i);
    else
        map[i] = val;
}

int[] chooseK(int n, int k)
{
    for (int i = 0; i < k; i++)
    {
        int randomIndex = nextRandom(0, n - i); //(n - i is exclusive)
        int desiredIndex = n-i-1;

        int valAtRandom = getValue(randomIndex);
        int valAtDesired = getValue(desiredIndex);

        setValue(desiredIndex, valAtRandom);
        setValue(randomIndex, valAtDesired);
    }

    int[] output = new int[k];
    for (int i = 0; i < k; i++)
    {
        output[i] = (getValue(n-i-1));
    }

    return output;
}

Ответ 12

Следующий код создает случайное число последовательности между [1, m], которое не было сгенерировано ранее.

public class NewClass {

    public List<Integer> keys = new ArrayList<Integer>();

    public int rand(int m) {
        int n = (int) (Math.random() * m + 1);
        if (!keys.contains(n)) {
            keys.add(n);
            return n;
        } else {
            return rand(m);
        }
    }

    public static void main(String[] args) {
        int m = 4;
        NewClass ne = new NewClass();
        for (int i = 0; i < 4; i++) {
            System.out.println(ne.rand(m));
        }
        System.out.println("list: " + ne.keys);
    }
}

Ответ 13

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

Ответ 14

Здесь - эффективное решение для быстрого создания рандомизированного массива. После рандомизации вы можете просто выбрать n -ный элемент e для массива, increment n и return e. Это решение имеет O (1) для получения случайного числа и O (n) для инициализации, но поскольку компромисс требует хорошего объема памяти, если n становится достаточно большим.

Ответ 15

Существует более эффективное и менее громоздкое решение для целых чисел, чем Collections.shuffle.

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

Этот алгоритм работает для загрузки любого массива и достижения случайного порядка в конце нагрузки. Он также работает для добавления в коллекцию List (или любой другой индексированной коллекции) и достижения случайной последовательности в коллекции в конце добавлений.

Это можно сделать с помощью одного массива, созданного один раз, или численно упорядоченного коллекционирования, такого как Список, на месте. Для массива размер исходного массива должен быть точного размера, чтобы содержать все заданные значения. Если вы не знаете, сколько значений может произойти заблаговременно, использование набора с упорядоченным числом, например ArrayList или List, где размер не является неизменным, также будет работать. Он будет работать универсально для массива любого размера до Integer.MAX_VALUE, который составляет чуть более 2 000 000 000. Объекты списка будут иметь одинаковые пределы индекса. Когда вы дойдете до массива такого размера, на вашем компьютере может закончиться нехватка памяти. Может быть более эффективным загрузить массив, набранный для типов объектов, и преобразовать его в некоторую коллекцию после загрузки массива. Это особенно верно, если целевая коллекция не индексируется численно.

Этот алгоритм, точно так же, как написано, создаст очень ровное распределение, где нет дубликатов. Один из аспектов, который ОЧЕНЬ ВАЖНО, заключается в том, что он должен иметь возможность вхождения следующего элемента в текущий текущий размер + 1. Таким образом, для второго элемента можно было бы сохранить его в местоположении 0 или местоположении 1. Для 20-го элемента можно сохранить его в любом месте, от 0 до 19. Как можно больше первый элемент останется в местоположении 0, так как он может оказаться в любом другом месте. Это возможно, так как следующий новый пункт отправится куда угодно, включая следующее новое место.

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

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

// RandomSequence.java
import java.util.Random;
public class RandomSequence {

    public static void main(String[] args) {
        // create an array of the size and type for which
        // you want a random sequence
        int[] randomSequence = new int[20];
        Random randomNumbers = new Random();

        for (int i = 0; i < randomSequence.length; i++ ) {
            if (i == 0) { // seed first entry in array with item 0
                randomSequence[i] = 0; 
            } else { // for all other items...
                // choose a random pointer to the segment of the
                // array already containing items
                int pointer = randomNumbers.nextInt(i + 1);
                randomSequence[i] = randomSequence[pointer]; 
                randomSequence[pointer] = i;
                // note that if pointer & i are equal
                // the new value will just go into location i and possibly stay there
                // this is VERY IMPORTANT to ensure the sequence is really random
                // and not biased
            } // end if...else
        } // end for
        for (int number: randomSequence) {
                System.out.printf("%2d ", number);
        } // end for
    } // end main
} // end class RandomSequence

Ответ 16

На самом деле все зависит от того, для чего вам нужно случайное поколение, но вот мое взятие.

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

public static int newRandom(int limit){
    return generatedRandom.nextInt(limit);  }

Далее вам нужно создать очень простую структуру решений, которая сравнивает значения. Это можно сделать одним из двух способов. Если у вас есть очень ограниченное количество чисел для проверки, достаточно простого оператора IF:

public static int testDuplicates(int int1, int int2, int int3, int int4, int int5){
    boolean loopFlag = true;
    while(loopFlag == true){
        if(int1 == int2 || int1 == int3 || int1 == int4 || int1 == int5 || int1 == 0){
            int1 = newRandom(75);
            loopFlag = true;    }
        else{
            loopFlag = false;   }}
    return int1;    }

Вышеперечисленное сравнивает int1 с int2 через int5, а также гарантирует, что в randoms нет нулей.

Используя эти два метода, мы можем сделать следующее:

    num1 = newRandom(limit1);
    num2 = newRandom(limit1);
    num3 = newRandom(limit1);
    num4 = newRandom(limit1);
    num5 = newRandom(limit1);

Далее:

        num1 = testDuplicates(num1, num2, num3, num4, num5);
        num2 = testDuplicates(num2, num1, num3, num4, num5);
        num3 = testDuplicates(num3, num1, num2, num4, num5);
        num4 = testDuplicates(num4, num1, num2, num3, num5);
        num5 = testDuplicates(num5, num1, num2, num3, num5);

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

Надеюсь, это поможет. Этот сайт очень помог мне, я чувствовал себя обязанным, по крайней мере, ПОПРОБОВАТЬ, чтобы помочь.

Ответ 17

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

Нет класса генератора случайного дублирования