std::random_shuffle, std::shuffle
Определено в заголовке <algorithm> | ||
|---|---|---|
template< class RandomIt > void random_shuffle( RandomIt first, RandomIt last ); | (1) |
(устарело в C++14) (удалено в C++17) |
| (2) | ||
template< class RandomIt, class RandomFunc > void random_shuffle( RandomIt first, RandomIt last, RandomFunc& r ); | (до 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.g.Параметры
| first, last | - | диапазон элементов, которые нужно случайным образом переупорядочить |
| r | - | объект-функция, возвращающая случайно выбранное значение типа, преобразуемого в std::iterator_traits<RandomIt>::difference_type в интервале [0, n) при вызове как r(n) |
| g | - | генератор случайных битов равномерного распределения тип результата которого преобразуется в std::iterator_traits<RandomIt>::difference_type |
| Требования к типу | ||
-RandomIt должен удовлетворять требованиям ValueSwappable и LegacyRandomAccessIterator. |
||
-std::remove_reference_t<URBG> должен удовлетворять требованиям генератора случайных битов равномерного распределения. |
||
Возвращаемое значение
(нет)
Сложность
Линейна относительно расстояния между first и last.
Примечания
Обратите внимание, что реализация не диктуется стандартом, поэтому, даже если вы используете точно такие же RandomFunc или URBG (генератор случайных чисел равномерного распределения), вы можете получить разные результаты с различными реализациями стандартной библиотеки.
Причина удаления std::random_shuffle в C++17 заключается в том, что версия только для итераторов обычно зависит от std::rand, которая теперь также рассматривается для устаревания. (std::rand следует заменить классами из заголовка <random>, поскольку std::rand считается вредным.) Кроме того, версия только для итераторов std::random_shuffle обычно зависит от глобального состояния. Алгоритм перемешивания std::shuffle является предпочтительной заменой, так как он использует URBG в качестве своего 3-го параметра.
Возможная реализация
См. также реализации в 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))]);
}
} |
Пример
Случайным образом перемешивает последовательность [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) | случайным образом переупорядочивает элементы в диапазоне (неблокирующая) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/algorithm/random_shuffle