Namespaces
Variants

std::random_shuffle, std::shuffle

С сайта ru.cppreference.net
(Перенаправлено с cpp/algorithm/shuffle)
 
 
Библиотека алгоритмов
Ограниченные алгоритмы и алгоритмы над диапазонами (C++20)
Ограниченные алгоритмы, например ranges::copy, ranges::sort, ...
Операции над последовательностями без изменения    
Пакетные операции
(C++17)
Операции поиска
Операции изменения последовательностей
Операции копирования
(C++11)
(C++11)
Операции обмена
Операции преобразования
Операции генерации
Операции удаления
Операции изменения порядка
(до C++17)(C++11)
(C++20)(C++20)
Операции выборки
(C++17)

Сортировка и связанные операции
Операции разделения
(C++11)    

Операции сортировки
Операции двоичного поиска
(на разделённых диапазонах)
Операции над множествами (на отсортированных диапазонах)
Операции слияния (на отсортированных диапазонах)
Операции над кучей
Операции минимума/максимума
(C++11)
(C++17)
Операции лексикографического сравнения
Операции перестановки


Политики выполнения (C++17)
(только для демонстрации*)(C++26)

Численные операции
(C++11)
(C++17)
(C++17)    

Специализированные <memory> алгоритмы

Специализированные <random> алгоритмы
Библиотека C









 
Определено в заголовке <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) так, что каждая возможная перестановка этих элементов имеет равную вероятность появления.

1) Источник случайности определяется реализацией, но часто используется функция std::rand.
2) Источником случайности является объект-функция r.
Если выполняется любое из следующих условий, поведение не определено:
  • Тип возвращаемого значения r не преобразуется в std::iterator_traits<RandomIt>::difference_type.
  • Для положительного значения n типа std::iterator_traits<RandomIt>::difference_type результат r(n) не является случайно выбранным значением в интервале [0, n).
3) Источником случайности является объект g.
Пусть тип T будет std::remove_reference_t<URBG>, если выполняется любое из следующих условий, поведение не определено:
  • T::result_type не преобразуется в std::iterator_traits<RandomIt>::difference_type.
(до C++20)

Если тип *first не является Swappable(до C++11)RandomIt не является ValueSwappable(начиная с 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's 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]
требуется
  1. ↑ Перегрузка (3) имеет тот же дефект, но эта часть исправления не применима к C++98.

Смотрите также

генерирует следующую бо́льшую лексикографическую перестановку диапазона элементов
(шаблон функции & алгоритм, объект-функция)
генерирует следующую ме́ньшую лексикографическую перестановку диапазона элементов
(шаблон функции & алгоритм, объект-функция)
случайно переупорядочивает элементы в диапазоне
(алгоритм, объект-функция)