std::random_shuffle, std::shuffle
| Défini dans l'en-tête <algorithm>
|
||
template< class RandomIt >
void random_shuffle( RandomIt first, RandomIt last );
|
(1) | (déprécié en C++14) (supprimé en C++17) |
template< class RandomIt, class RandomFunc >
void random_shuffle( RandomIt first, RandomIt last, RandomFunc& r );
|
(2) | (jusqu'à C++11) |
template< class RandomIt, class RandomFunc >
void random_shuffle( RandomIt first, RandomIt last, RandomFunc&& r );
|
(depuis C++11) (déprécié en C++14) (supprimé en C++17) |
|
template< class RandomIt, class URBG >
void shuffle( RandomIt first, RandomIt last, URBG&& g );
|
(3) | (depuis C++11) |
Réordonne les éléments dans la plage [first, last) donnée de sorte que chaque permutation possible de ces éléments ait une probabilité égale d'apparition.
r.- Le type de retour de
rn'est pas convertible enstd::iterator_traits<RandomIt>::difference_type. - Étant donné une valeur positive
nde typestd::iterator_traits<RandomIt>::difference_type, le résultat der(n)n'est pas une valeur choisie aléatoirement dans l'intervalle[0,n).
g.T comme std::remove_reference_t<URBG>, si l'une des conditions suivantes est satisfaite, le comportement est indéfini :
Tn'est pas un UniformRandomBitGenerator.
|
(jusqu'à C++20) |
Si le type de *first n'est pas Swappable(jusqu'à C++11)RandomIt n'est pas ValueSwappable(depuis C++11), le comportement est indéfini.
Paramètres
| first, last | - | la paire d'itérateurs définissant la plage d'éléments à mélanger aléatoirement |
| r | - | objet fonction retournant une valeur choisie aléatoirement |
| g | - | objet générateur retournant une valeur choisie aléatoirement |
| Exigences de type | ||
-RandomIt doit satisfaire les exigences de LegacyRandomAccessIterator.
| ||
Complexité
Exactement std::distance(first, last) - 1 échanges.
Implémentation possible
Voir aussi les implémentations dans libstdc++ et 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))]);
}
}
|
Notes
Notez que l'implémentation n'est pas dictée par la norme, donc même si vous utilisez exactement le même RandomFunc ou URBG (Générateur de nombres aléatoires uniforme), vous pouvez obtenir des résultats différents avec des implémentations de bibliothèque standard différentes.
La raison de la suppression de std::random_shuffle en C++17 est que la version uniquement itérateur dépend généralement de std::rand, qui est maintenant également discutée pour la dépréciation. (std::rand devrait être remplacé par les classes de l'en-tête <random>, car std::rand est considéré comme nuisible.) De plus, la version uniquement itérateur std::random_shuffle dépend généralement d'un état global. L'algorithme de mélange de std::shuffle est le remplacement préféré, car il utilise un URBG comme 3ème paramètre.
Exemple
Mélange aléatoirement la séquence [1, 10] d'entiers :
#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';
}
Sortie possible :
8 6 10 4 2 3 7 1 9 5
Rapports de défauts
Les rapports de défauts suivants modifiant le comportement ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Appliqué à | Comportement tel que publié | Comportement correct |
|---|---|---|---|
| LWG 395 | C++98 | la source d'aléa de la surcharge (1) n'était pas spécifiée, et std::rand ne pouvait pas être la source en raison de l'exigence de la bibliothèque C |
elle est définie par l'implémentation, et l'utilisation de std::rand est autorisée |
| LWG 552 (N2423) |
C++98 | r n'était pas obligée d'être la sourced'aléa de la surcharge (2)[1] |
obligatoire |
- ↑ La surcharge (3) a le même défaut, mais cette partie de la résolution ne s'applique pas à C++98.
Voir aussi
| génère la permutation lexicographique suivante plus grande d'une plage d'éléments (gabarit de fonction & objet fonction d'algorithme) | |
(C++20) |
|
| génère la permutation lexicographique suivante plus petite d'une plage d'éléments (gabarit de fonction & objet fonction d'algorithme) | |
(C++20) |
|
(C++20) |
réordonne aléatoirement les éléments dans une plage (objet fonction d'algorithme) |