Std:: random_shuffle производит одинаковый результат каждый раз

Возможный дубликат:
Как убедиться, что std:: random_shuffle всегда производит другой результат?

У меня есть массив, и я хочу перетасовать его, я использую:

answerPositionArray[0] = 100;
answerPositionArray[1] = 400;
answerPositionArray[2] = 800;
std::random_shuffle(answerPositionArray, answerPositionArray + 2);

Но каждый раз, когда я запускаю свою программу, выдается та же тасовка, 400, 800, 100. Есть ли способ каждый раз перетасовать? Например. первый раз 100, 800, 400, затем 800, 400, 100 и т.д.

Спасибо

Ответ 1

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

Итак, как установить семя? Использование:

srand(time(0));

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

Ответ 2

std::random_shuffle(b,e) использует источник случайности, определенный реализацией, и поэтому его нельзя контролировать с возможностью портативного управления. Обычно реализации используют std::rand(), поэтому использование std::srand() для засева rng часто работает.

// not portable, depends on implementation defined source of randomness in random_shuffle
std::srand(some_seed);
std::random_shuffle(answerPositionArray, answerPositionArray+size);

Существует перегрузка std::random_shuffle(), которая принимает в качестве третьего параметра генератор случайных чисел. Вы можете использовать эту форму для определения источника случайности, чтобы вы могли ее засеять.

struct RNG {
    int operator() (int n) {
        return std::rand() / (1.0 + RAND_MAX) * n;
    }
};

std::srand(seed);
std::random_shuffle(answerPositionArray, answerPositionArray+size, RNG());

С++ 11 вводит другой алгоритм std::shuffle, который принимает UniformRandomNumberGenerator, позволяя использовать генераторы С++ 11 <random>:

std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 eng(seed);

std::shuffle(std::begin(answerPositionArray), std::end(answerPositionArray), eng);

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

Это хорошая демонстрация того, как использовать магические числа, как в вашем коде:

std::random_shuffle(answerPositionArray, answerPositionArray + 2);
                                                               ^
                                                               |
                                                 magic number --

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

// trick for getting an array size
template<typename T, int N> int array_size(T (&)[N]) { return N; }

int answerPositionArray[] = {100, 400, 800};

std::random_shuffle(answerPositionArray,
                    answerPositionArray + array_size(answerPositionArray));

Или как только вы можете использовать С++ 11, вы можете использовать std::begin и std::end для массивов:

std::random_shuffle(std::begin(answerPositionArray), std::end(answerPositionArray));

Или вы можете реализовать функции begin и end самостоятельно в С++ 03 с использованием вышеупомянутого тэка размера массива:

template<typename T, int N> T *begin(T (&a)[N]) { return a; }
template<typename T, int N> T   *end(T (&a)[N]) { return a + N; }

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