Namespaces
Variants

std::random_shuffle, std::shuffle

ja.cppreference.net より
 
 
アルゴリズムライブラリ
制約付きアルゴリズムと範囲アルゴリズム (C++20)
制約付きアルゴリズム、例:ranges::copy、ranges::sort、...
ソートと関連操作
分割操作
(C++11)    

ソート操作
二分探索操作
(分割された範囲に対して)
集合操作(ソート済み範囲に対して)
マージ操作(ソート済み範囲に対して)
ヒープ操作
最小値/最大値操作
(C++11)
(C++17)
辞書式比較操作
順列操作


 
ヘッダ <algorithm>
template< class RandomIt >
void random_shuffle( RandomIt first, RandomIt last );
で定義 (1) (C++14で非推奨)
(C++17で削除)
template< class RandomIt, class RandomFunc >
void random_shuffle( RandomIt first, RandomIt last, RandomFunc& r );
(2) (C++11まで)
template< class RandomIt, class RandomFunc >
void random_shuffle( RandomIt first, RandomIt last, RandomFunc&& r );
(C++11から)
(C++14で非推奨)
(C++17で削除)
template< class RandomIt, class URBG >
void shuffle( RandomIt first, RandomIt last, URBG&& g );
(3) (C++11から)

指定範囲 [first, last) の要素を並べ替え、各順列が等確率で出現するようにします。

1) 乱数の生成源は実装定義ですが、関数 std::rand がよく使用されます。
2) 乱数の生成源は関数オブジェクト r です。
以下の条件のいずれかが満たされる場合、動作は未定義です:
  • rの戻り値の型が std::iterator_traits<RandomIt>::difference_type に変換可能でない。
  • 正の値 n(型は std::iterator_traits<RandomIt>::difference_type)が与えられたとき、r(n)の結果が区間 [0, n) 内のランダムに選ばれた値でない。
3) 乱数の生成源はオブジェクト g です。
型 T を std::remove_reference_t<URBG> とすると、以下の条件のいずれかが満たされる場合、動作は未定義です:
  • T::result_typestd::iterator_traits<RandomIt>::difference_type に変換可能でない。
(C++20まで)

*firstの型が Swappable ではない (C++11まで)RandomItValueSwappable ではない (C++11から) 場合、動作は未定義です。

パラメータ

first, last - 要素をランダムにシャッフルする範囲を定義するイテレータのペア
r - ランダムに選択された値を返す関数オブジェクト
g - ランダムに選択された値を返すジェネレータオブジェクト
型要件
-
RandomIt は LegacyRandomAccessIterator の要件を満たさなければならない。

計算量

正確に std:: distance ( first, last ) - 1 回のスワップ。

実装例

実装例については libstdc++ および 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) は実際には正しくありません。なぜなら、生成される数値が
        // ほとんどの i の値に対して均一に分布しないためです。正しいコードは
        // C++11 std::uniform_int_distribution 実装のバリエーションになります。
    }
}
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))]);
    }
}

注記

実装は標準で規定されていないため、たとえ同じ RandomFunc または URBG (一様乱数生成器)を使用した場合でも、標準ライブラリの実装が異なれば結果が異なる可能性があることに注意してください。

C++17でstd::random_shuffleが削除された理由は、イテレータのみのバージョンが通常std::randに依存しているためです。std::randは非推奨の検討がなされています(std::randは有害と見なされているため、<random>ヘッダーのクラスで置き換えるべきです)。さらに、イテレータのみのstd::random_shuffleバージョンは通常、グローバル状態に依存します。std::shuffleのシャッフルアルゴリズムは、第3引数としてURBGを使用するため、推奨される代替手段です。

例

整数のシーケンス [ 1 , 10 ] をランダムにシャッフルします:

#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';
}

出力例:

8 6 10 4 2 3 7 1 9 5

不具合報告

以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。

DR 適用対象 公開時の動作 正しい動作
LWG 395 C++98 オーバーロード (1) の乱数ソースが指定されておらず、
std::rand はCライブラリの要件によりソースになり得なかった
実装定義であり、
std::rand の使用が許可される
LWG 552
( N2423 )
C++98 r がオーバーロード (2) の乱数ソースであることが要求されていなかった
[1]
要求される
  1. ↑ オーバーロード (3) も同じ欠陥を持っていますが、その解決策の一部はC++98には適用されません。

関連項目

範囲の要素の辞書式順序で次の大きな順列を生成する
(関数テンプレート & アルゴリズム関数オブジェクト)
範囲の要素の辞書式順序で次の小さな順列を生成する
(関数テンプレート & アルゴリズム関数オブジェクト)
範囲の要素をランダムに並べ替える
(アルゴリズム関数オブジェクト)