Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/algorithm/random shuffle"

From cppreference.com
< cpp‎ | algorithm
m (Notes: fmt.)
m (minor wording tweaks)
Line 51: Line 51:
 
Note that the implementation is not dictated by the standard, so even if you use exactly the same {{tt|RandomFunc}} or {{tt|URBG}} (Uniform Random Number Generator) you may get different results with different standard library implementations.  
 
Note that the implementation is not dictated by the standard, so even if you use exactly the same {{tt|RandomFunc}} or {{tt|URBG}} (Uniform Random Number Generator) you may get different results with different standard library implementations.  
  
The reason for removing {{lc|random_shuffle}} in C++17 is, that the iterator only version is usually depending on {{lc|std::rand}}, which is now also discussed for deprecation, and should be replaced with the classes of the [[cpp/header/random|{{tt|<random>}}]] header, as {{lc|std::rand}} is ''considered harmful''. Also the iterator-only {{lc|random_shuffle}} version usually depends on a global state. The shuffle algorithm is the replacement, and has {{tt|URBG}} as its 3rd parameter.
+
The reason for removing {{lc|random_shuffle}} in C++17 is that the iterator-only version usually depends on {{lc|std::rand}}, which is now also discussed for deprecation. ({{lc|std::rand}} should be replaced with the classes of the [[cpp/header/random|{{tt|<random>}}]] header, as {{lc|std::rand}} is ''considered harmful''.) In addition, the iterator-only {{lc|random_shuffle}} version usually depends on a global state. The {{lc|std::shuffle}} shuffle algorithm is the preferred replacement, as it uses a {{tt|URBG}} as its 3rd parameter.
  
 
===Possible implementation===
 
===Possible implementation===

Revision as of 07:36, 11 October 2021

 
 
Algorithm library
Constrained algorithms and algorithms on ranges (C++20)
Constrained algorithms, e.g. ranges::copy, ranges::sort, ...
Execution policies (C++17)
Non-modifying sequence operations
Batch operations
(C++17)
Search operations
(C++11)                (C++11)(C++11)

Modifying sequence operations
Copy operations
(C++11)
(C++11)
Swap operations
Transformation operations
Generation operations
Removing operations
Order-changing operations
random_shuffleshuffle
(until C++17)(C++11)
(C++20)(C++20)
Sampling operations
(C++17)

Sorting and related operations
Partitioning operations
Sorting operations
Binary search operations
(on partitioned ranges)
Set operations (on sorted ranges)
Merge operations (on sorted ranges)
Heap operations
Minimum/maximum operations
(C++11)
(C++17)
Lexicographical comparison operations
Permutation operations
C library
Numeric operations
Operations on uninitialized memory
 
Defined in header <algorithm>
template< class RandomIt >
void random_shuffle( RandomIt first, RandomIt last );
(1) (deprecated in C++14)
(removed in C++17)
(2)
template< class RandomIt, class RandomFunc >
void random_shuffle( RandomIt first, RandomIt last, RandomFunc& r );
(until C++11)
template< class RandomIt, class RandomFunc >
void random_shuffle( RandomIt first, RandomIt last, RandomFunc&& r );
(since C++11)
(deprecated in C++14)
(removed in C++17)
template< class RandomIt, class URBG >
void shuffle( RandomIt first, RandomIt last, URBG&& g );
(3) (since C++11)

Reorders the elements in the given range [first, last) such that each possible permutation of those elements has equal probability of appearance.

1) The random number generator is implementation-defined, but the function std::rand is often used.
2) The random number generator is the function object r.
3) The random number generator is the function object g.

Contents

Parameters

first, last - the range of elements to shuffle randomly
r - function object returning a randomly chosen value of type convertible to std::iterator_traits<RandomIt>::difference_type in the interval [0,n) if invoked as r(n)
g - a UniformRandomBitGenerator whose result type is convertible to std::iterator_traits<RandomIt>::difference_type
Type requirements
-
RandomIt must meet the requirements of ValueSwappable and LegacyRandomAccessIterator.
-
std::remove_reference_t<URBG> must meet the requirements of UniformRandomBitGenerator.

Return value

(none)

Complexity

Linear in the distance between first and last.

Notes

Note that the implementation is not dictated by the standard, so even if you use exactly the same RandomFunc or URBG (Uniform Random Number Generator) you may get different results with different standard library implementations.

The reason for removing random_shuffle in C++17 is that the iterator-only version usually depends on std::rand, which is now also discussed for deprecation. (std::rand should be replaced with the classes of the <random> header, as std::rand is considered harmful.) In addition, the iterator-only random_shuffle version usually depends on a global state. The std::shuffle shuffle algorithm is the preferred replacement, as it uses a URBG as its 3rd parameter.

Possible implementation

See also the implementations in libstdc++ and libc++.

First version
template< class RandomIt >
void random_shuffle( RandomIt first, RandomIt last )
{
    typename std::iterator_traits<RandomIt>::difference_type i, n;
    n = last - first;
    for (i = n-1; i > 0; --i) {
        using std::swap;
        swap(first[i], first[std::rand() % (i+1)]);
        // rand() % (i+1) isn't actually correct, because the generated number
        // is not uniformly distributed for most values of i. A correct implementation
        // will need to essentially reimplement C++11 std::uniform_int_distribution,
        // which is beyond the scope of this example.
    }
}
Second version
template<class RandomIt, class RandomFunc>
void random_shuffle(RandomIt first, RandomIt last, RandomFunc&& r)
{
    typename std::iterator_traits<RandomIt>::difference_type i, n;
    n = last - first;
    for (i = n-1; i > 0; --i) {
        using std::swap;
        swap(first[i], first[r(i+1)]);
    }
}
Third version
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;
    diff_t n = last - first;
    for (diff_t i = n-1; i > 0; --i) {
        using std::swap;
        swap(first[i], first[D(g, param_t(0, i))]);
    }
}

Example

The following code randomly shuffles the integers 1..10:

#include <random>
#include <algorithm>
#include <iterator>
#include <iostream>
#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";
}

Possible output:

8 6 10 4 2 3 7 1 9 5

See also

generates the next greater lexicographic permutation of a range of elements
(function template) [edit]
generates the next smaller lexicographic permutation of a range of elements
(function template) [edit]
randomly re-orders elements in a range
(niebloid)[edit]