std::random_shuffle, std::shuffle
| Definiert in Header <algorithm>
|
||
template< class RandomIt >
void random_shuffle( RandomIt first, RandomIt last );
|
(1) | (veraltet in C++14) (entfernt in C++17) |
template< class RandomIt, class RandomFunc >
void random_shuffle( RandomIt first, RandomIt last, RandomFunc& r );
|
(2) | (bis C++11) |
template< class RandomIt, class RandomFunc >
void random_shuffle( RandomIt first, RandomIt last, RandomFunc&& r );
|
(seit C++11) (veraltet in C++14) (entfernt in C++17) |
|
template< class RandomIt, class URBG >
void shuffle( RandomIt first, RandomIt last, URBG&& g );
|
(3) | (seit C++11) |
Ordnet die Elemente im gegebenen Bereich [first, last) so um, dass jede mögliche Permutation dieser Elemente mit gleicher Wahrscheinlichkeit auftritt.
r.- Der Rückgabetyp von
rist nicht konvertierbar zustd::iterator_traits<RandomIt>::difference_type. - Gegeben ein positiver Wert
nvom Typstd::iterator_traits<RandomIt>::difference_type, ist das Ergebnis vonr(n)kein zufällig gewählter Wert im Intervall[0,n).
g.T als std::remove_reference_t<URBG>, ist das Verhalten undefiniert, wenn eine der folgenden Bedingungen erfüllt ist:
Tist kein UniformRandomBitGenerator.
|
(bis C++20) |
Wenn der Typ von *first nicht Swappable(bis C++11)RandomIt ist nicht ValueSwappable(seit C++11), ist das Verhalten undefiniert.
Parameter
| first, last | - | das Iteratorpaar, das den Bereich der zufällig zu mischenden Elemente definiert |
| r | - | Funktionsobjekt, das einen zufällig gewählten Wert zurückgibt |
| g | - | Generatorobjekt, das einen zufällig gewählten Wert zurückgibt |
| Typanforderungen | ||
-RandomIt muss die Anforderungen von LegacyRandomAccessIterator erfüllen.
| ||
Komplexität
Genau std::distance(first, last) - 1 Vertauschungen.
Mögliche Implementierung
Siehe auch die Implementierungen in libstdc++ und 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))]);
}
}
|
Anmerkungen
Beachten Sie, dass die Implementierung nicht durch den Standard vorgeschrieben ist. Selbst wenn Sie genau denselben RandomFunc oder URBG (Uniform Random Number Generator) verwenden, können Sie mit verschiedenen Implementierungen der Standardbibliothek unterschiedliche Ergebnisse erhalten.
Der Grund für die Entfernung von std::random_shuffle in C++17 ist, dass die nur-Iterator-Version normalerweise von std::rand abhängt, das jetzt ebenfalls zur Veraltung diskutiert wird. (std::rand sollte durch die Klassen des <random>-Headers ersetzt werden, da std::rand als schädlich angesehen wird.) Außerdem hängt die nur-Iterator-std::random_shuffle-Version normalerweise von einem globalen Zustand ab. Der Mischalgorithmus von std::shuffle ist der bevorzugte Ersatz, da er einen URBG als dritten Parameter verwendet.
Beispiel
Mischt die Sequenz [1, 10] von Ganzzahlen zufällig:
#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';
}
Mögliche Ausgabe:
8 6 10 4 2 3 7 1 9 5
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Richtiges Verhalten |
|---|---|---|---|
| LWG 395 | C++98 | die Zufallsquelle der Überladung (1) war nicht spezifiziert, und std::rand konnte aufgrund der C-Bibliotheksanforderung nicht die Quelle sein |
es ist implementierungsdefiniert, und die Verwendung von std::rand ist erlaubt |
| LWG 552 (N2423) |
C++98 | r war nicht erforderlich, die Quelleder Zufälligkeit der Überladung (2)[1] |
erforderlich |
- ↑ Überladung (3) hat denselben Fehler, aber dieser Teil der Lösung ist nicht auf C++98 anwendbar.
Siehe auch
| erzeugt die nächstgrößere lexikografische Permutation eines Bereichs von Elementen (Funktionstemplate & Algorithmus-Funktionsobjekt) | |
(C++20) |
|
| erzeugt die nächstkleinere lexikografische Permutation eines Bereichs von Elementen (Funktionstemplate & Algorithmus-Funktionsobjekt) | |
(C++20) |
|
(C++20) |
ordnet Elemente in einem Bereich zufällig neu an (Algorithmus-Funktionsobjekt) |