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; }
Эти методы позволяют избежать использования магического номера для размера массива, поэтому, когда вы пишете или изменяете код, вы вряд ли ошибетесь, используя неправильное значение.