14

重複の可能性:
std::random_shuffle が常に異なる結果を生成するようにするにはどうすればよいですか?

配列があり、それをシャッフルしたいので、次を使用します。

answerPositionArray[0] = 100;
answerPositionArray[1] = 400;
answerPositionArray[2] = 800;
std::random_shuffle(answerPositionArray, answerPositionArray + 2);

しかし、プログラムを実行するたびに、同じシャッフル、400、800、100 が出てきます。シャッフルを毎回異なるものにする方法はありますか? 例えば。最初は 100、800、400、次に 800、400、100 など。

ありがとう

4

2 に答える 2

38

std::random_shuffle(b,e)実装で定義されたランダム性のソースを使用するため、これを移植可能に制御することはできません。通常、実装は rng をシードするstd::rand()ために使用するため、多くの場合機能します。std::srand()

// not portable, depends on implementation defined source of randomness in random_shuffle
std::srand(some_seed);
std::random_shuffle(answerPositionArray, answerPositionArray+size);

std::random_shuffle()3 番目のパラメーターとして乱数ジェネレーターを取るオーバーロードがあります。このフォームを使用してランダム性のソースを定義し、それをシードすることができます。

struct RNG {
    int operator() (int n) {
        return std::rand() / (1.0 + RAND_MAX) * n;
    }
};

std::srand(seed);
std::random_shuffle(answerPositionArray, answerPositionArray+size, RNG());

std::shuffleC++11では、UniformRandomNumberGenerator を取る別のアルゴリズムが導入され、C++11<random>ジェネレーターを使用できるようになります。

std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 eng(seed);

std::shuffle(std::begin(answerPositionArray), std::end(answerPositionArray), eng);

あなたのコメントは、配列全体をシャッフルしていないこと、最初の2つの要素のみをシャッフルしていて、最後の要素に触れていないことが問題であることを示しています。

これは、コードのようにマジック ナンバーを使用する方法の良いデモンストレーションです。

std::random_shuffle(answerPositionArray, answerPositionArray + 2);
                                                               ^
                                                               |
                                                 magic number --

エラーが発生しやすい可能性があります。代わりに、そのような値とは無関係に機能するコードを書くようにしてください。

// trick for getting an array size
template<typename T, int N> int array_size(T (&)[N]) { return N; }

int answerPositionArray[] = {100, 400, 800};

std::random_shuffle(answerPositionArray,
                    answerPositionArray + array_size(answerPositionArray));

または、C++11 を使用できるようになったら、配列に対してstd::beginandを使用できます。std::end

std::random_shuffle(std::begin(answerPositionArray), std::end(answerPositionArray));

または、上記の配列サイズのトリックを使用して、C++03 で自分で実装beginして機能させることもできます。end

template<typename T, int N> T *begin(T (&a)[N]) { return a; }
template<typename T, int N> T   *end(T (&a)[N]) { return a + N; }

これらのメソッドを使用すると、配列サイズにマジック ナンバーを使用する必要がなくなるため、コードを記述または変更するときに、間違った値を誤って使用する可能性が低くなります。

于 2013-01-08T18:46:25.350 に答える
25

C++ の乱数は完全にランダムではありません。シードと呼ばれる初期値から生成されます。シードを設定しないと、常に同じになるため、生成されるシーケンスは変更されません。std::random_shuffle乱数生成に依存するため、このように動作します。

では、シードを設定するにはどうすればよいでしょうか。使用する:

srand(time(0));

乱数を使用して関数を呼び出す前。シードを現在の時間 (秒単位) に設定します。適切なヘッダー ファイルを追加することを忘れないでください。

于 2013-01-08T18:43:43.430 に答える