Namespaces
Variants

std::random_shuffle, std::shuffle

Von de.cppreference.net
 
 
Algorithmusbibliothek
Eingeschränkte Algorithmen und Algorithmen auf Bereichen (C++20)
Eingeschränkte Algorithmen, z.B. ranges::copy, ranges::sort, ...
Nicht modifizierende Sequenzoperationen    
Stapeloperationen
(C++17)
Suchoperationen
Modifizierende Sequenzoperationen
Kopieroperationen
(C++11)
(C++11)
Tauschoperationen
Transformationsoperationen
Erzeugungsoperationen
Entfernungsoperationen
Reihenfolgenändernde Operationen
(bis C++17)(C++11)
(C++20)(C++20)
Stichprobenoperationen
(C++17)

Sortier- und verwandte Operationen
Partitionierungsoperationen
(C++11)    

Sortieroperationen
Binäre Suchoperationen
(auf partitionierten Bereichen)
Mengenoperationen (auf sortierten Bereichen)
Mischoperationen (auf sortierten Bereichen)
Heap-Operationen
Minimum/Maximum-Operationen
(C++11)
(C++17)
Lexikografische Vergleichsoperationen
Permutationsoperationen


 
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.

1) Die Quelle der Zufälligkeit ist implementierungsdefiniert, aber die Funktion std::rand wird oft verwendet.
2) Die Quelle der Zufälligkeit ist das Funktionsobjekt r.
Wenn eine der folgenden Bedingungen erfüllt ist, ist das Verhalten undefiniert:
  • Der Rückgabetyp von r ist nicht konvertierbar zu std::iterator_traits<RandomIt>::difference_type.
  • Gegeben ein positiver Wert n vom Typ std::iterator_traits<RandomIt>::difference_type, ist das Ergebnis von r(n) kein zufällig gewählter Wert im Intervall [0, n).
3) Die Quelle der Zufälligkeit ist das Objekt g.
Gegeben der Typ T als std::remove_reference_t<URBG>, ist das Verhalten undefiniert, wenn eine der folgenden Bedingungen erfüllt ist:
  • T::result_type ist nicht konvertierbar zu std::iterator_traits<RandomIt>::difference_type.
(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 Quelle
der Zufälligkeit der Überladung (2)[1]
erforderlich
  1. ↑ Ü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)
erzeugt die nächstkleinere lexikografische Permutation eines Bereichs von Elementen
(Funktionstemplate & Algorithmus-Funktionsobjekt)
ordnet Elemente in einem Bereich zufällig neu an
(Algorithmus-Funktionsobjekt)