std::random_shuffle, std::shuffle
Определено в заголовке <algorithm> | ||
|---|---|---|
template< class RandomIt > void random_shuffle( RandomIt first, RandomIt last ); | (1) |
(устарело в C++14) (удалено в C++17) |
template< class RandomIt, class RandomFunc > void random_shuffle( RandomIt first, RandomIt last, RandomFunc& r ); | (2) | (до C++11) |
template< class RandomIt, class RandomFunc > void random_shuffle( RandomIt first, RandomIt last, RandomFunc&& r ); |
(начиная с C++11) (устарело в C++14) (удалено в C++17) | |
template< class RandomIt, class URBG > void shuffle( RandomIt first, RandomIt last, URBG&& g ); | (3) | (начиная с C++11) |
Изменяет порядок элементов в заданном диапазоне [first, last) так, что каждая возможная перестановка этих элементов имеет равную вероятность появления.
std::rand.r.- Возвращаемый тип
rне преобразуется к std::iterator_traits<RandomIt>::difference_type. - Для положительного значения
nтипа std::iterator_traits<RandomIt>::difference_type результатr(n)не является случайно выбранным значением из интервала[0,n).
g.T, заданного как std::remove_reference_t<URBG>, если выполняется любое из следующих условий, поведение не определено: -
Tне является генератором равномерных случайных битов.
| (до C++20) |
Если тип *first не является обмениваемым(до C++11)RandomIt не является обмениваемым значением(начиная с C++11), поведение не определено.
Параметры
| first, last | - | пара итераторов, задающая диапазон элементов для случайного перемешивания |
| r | - | функциональный объект, возвращающий случайно выбранное значение |
| g | - | объект-генератор, возвращающий случайно выбранное значение |
| Требования к типам | ||
-RandomIt должен соответствовать требованиям LegacyRandomAccessIterator. |
||
Сложность
Ровно std::distance(first, last) - 1 обменов.
Возможная реализация
Также см. реализации в libstdc++ и libc++.
| random_shuffle (1) |
|---|
template<class RandomIt>
void random_shuffle(RandomIt first, RandomIt last)
{
typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
for (diff_t i = last - first - 1; i > 0; --i)
{
using std::swap;
swap(first[i], first[std::rand() % (i + 1)]);
// rand() % (i + 1) is not actually correct, because the generated number is
// not uniformly distributed for most values of i. The correct code would be
// a variation of the C++11 std::uniform_int_distribution implementation.
}
}
|
| random_shuffle (2) |
template<class RandomIt, class RandomFunc>
void random_shuffle(RandomIt first, RandomIt last, RandomFunc&& r)
{
typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
for (diff_t i = last - first - 1; i > 0; --i)
{
using std::swap;
swap(first[i], first[r(i + 1)]);
}
}
|
| shuffle (3) |
template<class RandomIt, class URBG>
void shuffle(RandomIt first, RandomIt last, URBG&& g)
{
typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
typedef std::uniform_int_distribution<diff_t> distr_t;
typedef typename distr_t::param_type param_t;
distr_t D;
for (diff_t i = last - first - 1; i > 0; --i)
{
using std::swap;
swap(first[i], first[D(g, param_t(0, i))]);
}
}
|
Примечания
Обратите внимание, что стандарт не предписывает реализацию, поэтому даже при использовании одного и того же RandomFunc или URBG (генератора равномерных случайных чисел) результаты могут различаться в разных реализациях стандартной библиотеки.
Причина удаления std::random_shuffle в C++17 заключается в том, что версия, принимающая только итераторы, обычно зависит от std::rand, который теперь также предлагается признать устаревшим. (std::rand следует заменить классами из заголовка <random>, поскольку std::rand считается вредным.) Кроме того, версия std::random_shuffle, принимающая только итераторы, обычно зависит от глобального состояния. Алгоритм перемешивания из std::shuffle является предпочтительной заменой, поскольку в качестве третьего параметра он использует URBG.
Пример
Случайным образом перемешивает последовательность целых чисел [1, 10]:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <random>
#include <vector>
int main()
{
std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
}
Возможный вывод:
8 6 10 4 2 3 7 1 9 5
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были применены задним числом к ранее опубликованным стандартам C++.
| DR | Применён к | Опубликованное поведение | Корректное поведение |
|---|---|---|---|
| LWG 395 | C++98 | источник случайных значений для перегрузки (1) не был указан, аstd::rand не мог быть источником из-за требований библиотеки C | он определяется реализацией, и использовать std::rand разрешено |
|
LWG 552 (N2423) | C++98 |
r не требовалось использовать в качестве источникаслучайных значений для перегрузки (2)[1] | требовалось |
- Перегрузка (3) имеет тот же дефект, но эта часть решения неприменима к C++98.
См. также
| создаёт следующую лексикографически большую перестановку элементов диапазона (шаблон функции и функциональный объект-алгоритм) |
|
|
(C++20) | |
| создаёт следующую лексикографически меньшую перестановку элементов диапазона (шаблон функции и функциональный объект-алгоритм) |
|
|
(C++20) | |
|
(C++20) | случайным образом меняет порядок элементов диапазона (функциональный объект-алгоритм) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/algorithm/random_shuffle