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) neu an, sodass jede mögliche Permutation dieser Elemente die gleiche Wahrscheinlichkeit des Auftretens hat.
r.- Der Rückgabetyp von
rist nicht instd::iterator_traits<RandomIt>::difference_typekonvertierbar. - Bei einem positiven Wert
nvom Typstd::iterator_traits<RandomIt>::difference_typeist das Ergebnis vonr(n)kein zufällig gewählter Wert im Intervall[0,n).
g.T als std::remove_reference_t<URBG>, wenn eine der folgenden Bedingungen erfüllt ist, ist das Verhalten undefiniert:
Tist kein UniformRandomBitGenerator.
|
(bis C++20) |
Falls der Typ von *first nicht Swappable(bis C++11)RandomIt nicht ValueSwappable(seit C++11) ist, ist das Verhalten undefiniert.
Parameter
| first, last | - | das Paar von Iteratoren, die den Bereich der zufällig zu mischenden Elemente definieren |
| 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 Standardbibliotheksimplementierungen unterschiedliche Ergebnisse erhalten.
Der Grund für die Entfernung von std::random_shuffle in C++17 ist, dass die iterator-only-Version normalerweise von std::rand abhängt, das jetzt ebenfalls zur Abschaffung 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 iterator-only std::random_shuffle-Version normalerweise von einem globalen Zustand ab. Der std::shuffle's-shuffle-Algorithmus ist der bevorzugte Ersatz, da er ein 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
Fehlermeldungen (Defect Reports)
Die folgenden verhaltensändernden Fehlermeldungen wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Richtiges Verhalten |
|---|---|---|---|
| LWG 395 | C++98 | die Quelle der Zufälligkeit der Überladung (1) war nicht spezifiziert, und std::rand konnte aufgrund der C-Bibliotheksanforderung nicht die Quelle sein |
sie 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 auf C++98 nicht anwendbar.
Siehe auch
| erzeugt die nächstgrößere lexikografische Permutation eines Bereichs von Elementen (Funktionsvorlage & Algorithmusfunktionsobjekt) | |
(C++20) |
|
| erzeugt die nächstkleinere lexikografische Permutation eines Bereichs von Elementen (Funktionsvorlage & Algorithmusfunktionsobjekt) | |
(C++20) |
|
(C++20) |
ordnet Elemente in einem Bereich zufällig neu an (Algorithmusfunktionsobjekt) |