Namespaces
Variants
Views
Actions

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

From cppreference.com
< cpp‎ | algorithm
(Possible implementation for the first version;few changes in wording)
(Wording update.)
 
(35 intermediate revisions by 15 users not shown)
Line 2: Line 2:
 
{{cpp/algorithm/navbar}}
 
{{cpp/algorithm/navbar}}
 
{{dcl begin}}
 
{{dcl begin}}
{{dcl header | algorithm}}
+
{{dcl header|algorithm}}
{{dcl | num=1 | notes={{mark|deprecated in C++14}} |
+
{{dcla|num=1|until=c++17|deprecated=c++14|
 
template< class RandomIt >
 
template< class RandomIt >
 
void random_shuffle( RandomIt first, RandomIt last );
 
void random_shuffle( RandomIt first, RandomIt last );
 
}}
 
}}
{{dcl rev begin | num=2}}
+
{{dcl rev begin|num=2}}
{{dcl | until=c++11 |
+
{{dcla|until=c++11|anchor=2|
 
template< class RandomIt, class RandomFunc >
 
template< class RandomIt, class RandomFunc >
 
void random_shuffle( RandomIt first, RandomIt last, RandomFunc& r );
 
void random_shuffle( RandomIt first, RandomIt last, RandomFunc& r );
 
}}
 
}}
{{dcl | since=c++11 | notes={{mark|deprecated in C++14}} |
+
{{dcl|since=c++11|until=c++17|deprecated=c++14|
 
template< class RandomIt, class RandomFunc >
 
template< class RandomIt, class RandomFunc >
 
void random_shuffle( RandomIt first, RandomIt last, RandomFunc&& r );
 
void random_shuffle( RandomIt first, RandomIt last, RandomFunc&& r );
 
}}
 
}}
 
{{dcl rev end}}
 
{{dcl rev end}}
{{dcl | num=3 | since=c++11 |
+
{{dcla|num=3|since=c++11|
template< class RandomIt, class URNG >
+
template< class RandomIt, class URBG >
void shuffle( RandomIt first, RandomIt last, URNG&& g );
+
void shuffle( RandomIt first, RandomIt last, URBG&& g );
 
}}
 
}}
 
{{dcl end}}
 
{{dcl end}}
  
Reorders the elements in the given range {{tt|[first, last)}} such that each possible permutation of those elements has equal probability of appearance.
+
Reorders the elements in the given range {{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 {{lc|std::rand}} is often used.
+
@1@ The source of randomness is implementation-defined, but the function {{lc|std::rand}} is often used.
  
@2@ The random number generator is the function object {{tt|r}}.  
+
@2@ The source of randomness is the function object {{c|r}}.
 +
@@ If any of the following conditions is satisfied, the behavior is undefined:
 +
* The return type of {{c|r}} is not convertible to {{c/core|std::iterator_traits<RandomIt>::difference_type}}.
 +
* Given a positive value {{c|n}} of type {{c/core|std::iterator_traits<RandomIt>::difference_type}}, the result of {{c|r(n)}} is not a randomly chosen value in the interval {{range|0|n}}.
  
@3@ The random number generator is the function object {{tt|g}}.
+
@3@ The source of randomness is the object {{c|g}}.
 +
@@ Given the type {{tt|T}} as {{c/core|std::remove_reference_t<URBG>}}, if any of the following conditions is satisfied, the behavior is undefined:
 +
* {{tt|T}} is not a {{named req|UniformRandomBitGenerator}}.
 +
{{rrev|until=c++20|
 +
* {{tt|T::result_type}} is not convertible to {{c/core|std::iterator_traits<RandomIt>::difference_type}}.
 +
}}
 +
 
 +
If {{rev inl|until=c++11|the type of {{c|*first}} is not {{named req|Swappable}}}}{{rev inl|since=c++11|{{tt|RandomIt}} is not {{named req|ValueSwappable}}}}, the behavior is undefined.
  
 
===Parameters===
 
===Parameters===
 
{{par begin}}
 
{{par begin}}
{{par | first, last | the range of elements to shuffle randomly}}
+
{{par|first, last|the range of elements to shuffle randomly}}
{{par | r | function object returning a randomly chosen value of type convertible to  {{c|std::iterator_traits<RandomIt>::difference_type}} in the interval [0,n) if invoked as {{tt|r(n)}} }}
+
{{par|r|function object returning a randomly chosen value}}
{{par | g | a {{concept|UniformRandomNumberGenerator}} whose result type is convertible to {{c|std::iterator_traits<RandomIt>::difference_type}} }}
+
{{par|g|generator object returning a randomly chosen value}}
 
{{par hreq}}
 
{{par hreq}}
{{par req concept | RandomIt | RandomAccessIterator | ValueSwappable}}
+
{{par req named|RandomIt|RandomAccessIterator}}
{{par req concept | URNG | UniformRandomNumberGenerator}}
+
 
{{par end}}
 
{{par end}}
 
===Return value===
 
(none)
 
  
 
===Complexity===
 
===Complexity===
Linear in the distance between {{tt|first}} and {{tt|last}}
+
Exactly {{c|std::distance(first, last) - 1}} swaps.
  
 
===Possible implementation===
 
===Possible implementation===
{{eq fun
+
See also the implementations in [https://github.com/gcc-mirror/gcc/blob/d9375e490072d1aae73a93949aa158fcd2a27018/libstdc%2B%2B-v3/include/bits/stl_algo.h#L4551 libstdc++] and [https://github.com/llvm-mirror/libcxx/blob/a12cb9d211019d99b5875b6d8034617cbc24c2cc/include/algorithm#L3066 libc++].
| 1=
+
{{eq impl
template< class RandomIt >
+
|title1=random_shuffle (1)|ver1=1|1=
void random_shuffle( RandomIt first, RandomIt last )
+
template<class RandomIt>
 +
void random_shuffle(RandomIt first, RandomIt last)
 
{
 
{
     typename std::iterator_traits<RandomIt>::difference_type i, n;
+
     typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
     n = last - first;
+
      
     for (i = n-1; i > 0; --i) {
+
     for (diff_t i = last - first - 1; i > 0; --i)
 +
    {
 
         using std::swap;
 
         using std::swap;
         swap(first[i], first[std::rand() % (i+1)]);
+
         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.
 
     }
 
     }
 
}
 
}
| 2=
+
|title2=random_shuffle (2)|ver2=2|2=
 
template<class RandomIt, class RandomFunc>
 
template<class RandomIt, class RandomFunc>
 
void random_shuffle(RandomIt first, RandomIt last, RandomFunc&& r)
 
void random_shuffle(RandomIt first, RandomIt last, RandomFunc&& r)
 
{
 
{
     typename std::iterator_traits<RandomIt>::difference_type i, n;
+
     typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
     n = last - first;
+
      
     for (i = n-1; i > 0; --i) {
+
     for (diff_t i = last - first - 1; i > 0; --i)
 +
    {
 
         using std::swap;
 
         using std::swap;
         swap(first[i], first[r(i+1)]);
+
         swap(first[i], first[r(i + 1)]);
 
     }
 
     }
 
}
 
}
| 3=
+
|title3=shuffle (3)|ver3=3|3=
template<class RandomIt, class UniformRandomNumberGenerator>
+
template<class RandomIt, class URBG>
void shuffle(RandomIt first, RandomIt last,  
+
void shuffle(RandomIt first, RandomIt last, URBG&& g)
            UniformRandomNumberGenerator&& g)
+
 
{
 
{
 
     typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
 
     typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
     typedef typename std::make_unsigned<diff_t>::type udiff_t;
+
     typedef std::uniform_int_distribution<diff_t> distr_t;
    typedef typename std::uniform_int_distribution<udiff_t> distr_t;
+
 
     typedef typename distr_t::param_type param_t;
 
     typedef typename distr_t::param_type param_t;
 
+
   
 
     distr_t D;
 
     distr_t D;
    diff_t n = last - first;
+
     for (diff_t i = last - first - 1; i > 0; --i)
     for (diff_t i = n-1; i > 0; --i) {
+
    {
 
         using std::swap;
 
         using std::swap;
 
         swap(first[i], first[D(g, param_t(0, i))]);
 
         swap(first[i], first[D(g, param_t(0, i))]);
Line 89: Line 99:
 
}
 
}
 
}}
 
}}
 +
 +
===Notes===
 +
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 {{tt|std::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 {{header|random}} header, as {{lc|std::rand}} is ''considered harmful''.) In addition, the iterator-only {{tt|std::random_shuffle}} version usually depends on a global state. The {{tt|std::shuffle}}'s shuffle algorithm is the preferred replacement, as it uses a {{tt|URBG}} as its 3rd parameter.
  
 
===Example===
 
===Example===
 
{{example
 
{{example
| The following code randomly shuffles the integers 1..10:
+
|Randomly shuffles the sequence {{closed range plain|1|10}} of integers:
| code=
+
|code=
#include <random>
+
 
#include <algorithm>
 
#include <algorithm>
#include <iterator>
 
 
#include <iostream>
 
#include <iostream>
 +
#include <iterator>
 +
#include <random>
 +
#include <vector>
  
 
int main()
 
int main()
 
{
 
{
     std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+
     std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
 
+
   
 
     std::random_device rd;
 
     std::random_device rd;
 
     std::mt19937 g(rd());
 
     std::mt19937 g(rd());
 
+
   
 
     std::shuffle(v.begin(), v.end(), g);
 
     std::shuffle(v.begin(), v.end(), g);
 
+
   
 
     std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
 
     std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
     std::cout << "\n";
+
     std::cout << '\n';
 
}
 
}
| p=true
+
|p=true
| output=
+
|output=
 
8 6 10 4 2 3 7 1 9 5
 
8 6 10 4 2 3 7 1 9 5
 
}}
 
}}
 +
 +
===Defect reports===
 +
{{dr list begin}}
 +
{{dr list item|wg=lwg|dr=395|std=C++98|before=the source of randomness of overload {{v|1}} was not specified, and<br>{{lc|std::rand}} could not be the source due to the C library requirement|after=it is implementation-defined,<br>and using {{lc|std::rand}} is allowed}}
 +
{{dr list item|wg=lwg|dr=552|paper=N2423|std=C++98|before={{c|r}} was not required to be the source<br>of randomness of overload {{v|2}}<ref>Overload {{v|3}} has the same defect, but that part of the resolution is not applicable to C++98.</ref>|after=required}}
 +
{{dr list end}}
 +
<references/>
  
 
===See also===
 
===See also===
 
{{dsc begin}}
 
{{dsc begin}}
{{dsc inc | cpp/algorithm/dsc next_permutation}}
+
{{dsc inc|cpp/algorithm/dsc next_permutation}}
{{dsc inc | cpp/algorithm/dsc prev_permutation}}
+
{{dsc inc|cpp/algorithm/dsc prev_permutation}}
 +
{{dsc inc|cpp/algorithm/ranges/dsc shuffle}}
 
{{dsc end}}
 
{{dsc end}}
  
[[de:cpp/algorithm/random shuffle]]
+
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}
[[es:cpp/algorithm/random shuffle]]
+
[[fr:cpp/algorithm/random shuffle]]
+
[[it:cpp/algorithm/random shuffle]]
+
[[ja:cpp/algorithm/random shuffle]]
+
[[pt:cpp/algorithm/random shuffle]]
+
[[ru:cpp/algorithm/random shuffle]]
+
[[zh:cpp/algorithm/random shuffle]]
+

Latest revision as of 23:49, 27 March 2024

 
 
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 [firstlast) such that each possible permutation of those elements has equal probability of appearance.

1) The source of randomness is implementation-defined, but the function std::rand is often used.
2) The source of randomness is the function object r.
If any of the following conditions is satisfied, the behavior is undefined:
  • The return type of r is not convertible to std::iterator_traits<RandomIt>::difference_type.
  • Given a positive value n of type std::iterator_traits<RandomIt>::difference_type, the result of r(n) is not a randomly chosen value in the interval [0n).
3) The source of randomness is the object g.
Given the type T as std::remove_reference_t<URBG>, if any of the following conditions is satisfied, the behavior is undefined:
(until C++20)

If the type of *first is not Swappable(until C++11)RandomIt is not ValueSwappable(since C++11), the behavior is undefined.

Contents

[edit] Parameters

first, last - the range of elements to shuffle randomly
r - function object returning a randomly chosen value
g - generator object returning a randomly chosen value
Type requirements
-
RandomIt must meet the requirements of LegacyRandomAccessIterator.

[edit] Complexity

Exactly std::distance(first, last) - 1 swaps.

[edit] Possible implementation

See also the implementations in libstdc++ and 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))]);
    }
}

[edit] 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 std::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 std::random_shuffle version usually depends on a global state. The std::shuffle's shuffle algorithm is the preferred replacement, as it uses a URBG as its 3rd parameter.

[edit] Example

Randomly shuffles the sequence [110] of integers:

#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';
}

Possible output:

8 6 10 4 2 3 7 1 9 5

[edit] Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
LWG 395 C++98 the source of randomness of overload (1) was not specified, and
std::rand could not be the source due to the C library requirement
it is implementation-defined,
and using std::rand is allowed
LWG 552
(N2423)
C++98 r was not required to be the source
of randomness of overload (2)[1]
required
  1. Overload (3) has the same defect, but that part of the resolution is not applicable to C++98.

[edit] 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]