std::random_shuffle() algorithm
- od C++11
- do C++11
// (1)
template< class RandomIt >
void random_shuffle( RandomIt first, RandomIt last );
// (2)
template< class RandomIt, class RandomFunc >
void random_shuffle( RandomIt first, RandomIt last, RandomFunc&& r );
// (1)
template< class RandomIt >
void random_shuffle( RandomIt first, RandomIt last );
Reorders the elements in the given range [first
; last
) such that each possible permutation of those elements has equal probability of appearance.
-
(1) The source of randomness is implementation-defined
, but the functionstd::rand
is often used. -
(2) The source of randomness is the function object
r
.
Parameters
first last | The range of elements to shuffle. |
r | Function object returning a randomly chosen value of type convertible to |
Type requirements
RandomIt | LegacyRandomAccessIterator ValueSwappable |
Return value
(none)
Complexity
Linear in std::distance(first, last)
.
Exceptions
(none)
Possible implementation
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. A correct implementation
// will need to essentially reimplement C++11 std::uniform_int_distribution,
// which is beyond the scope of this example.
}
}
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)]);
}
}
Notes
Note that the implementation is not dictated by the standard, so even if you use exactly the same RandomFunc
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
shuffle algorithm is the preferred replacement, as it uses a URBG
as its 3rd parameter.
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
int main()
{
std::vector<int> v {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::random_shuffle(v.begin(), v.end());
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
Hover to see the original license.