読者です 読者をやめる 読者になる 読者になる

TR1の擬似乱数生成器でrandom_shuffle

C++

melt日記 - random_range_generator


C++0xTR1(Technical Report1)ライブラリにはというヘッダがあり
擬似乱数生成のためのクラスが多数用意されている

今回は、それらの擬似乱数生成器を使用したコンテナの並び替えを実装する



TR1の原型であるBoost C++ Librariesが提供している擬似乱数ライブラリには
random_number_generatorという便利なクラスがある

だが、TR1にはrandom_number_generatorが含まれないので、簡単だがこれを実装してみよう

template <class Engine, class ArgumentType=long>
class random_number_generator {
    Engine& engine_;
public:
    random_number_generator(Engine& engine) : engine_(engine) {}

    ArgumentType operator()(ArgumentType value)
    {
        return engine() % value;
    }
};


次に、TR1の擬似乱数生成器を使用したrandom_shuffleを実装する
(毎回EngineとGeneratorの変数を作るのがめんどくさいから作ったもの)

#include <algorithm> // std::random_shuffle

template <class Iterator, class Engine>
inline void random_shuffle_for_engine(Iterator first, Iterator last, Engine& engine)
{
    random_number_generator<Engine> gen(engine);
    std::random_shuffle(first, last, gen);
}


これで準備OK

使い方は以下のようになる

#include <ctime>
#include <vector>
#include <random> // mt19937

using namespace std;
using namespace std::tr1; // VC++9.0では必要, C++0xではTR1はstdネームスペースなのでこの行は不要

int main()
{
    vector<int> v;

    // メルセンヌ・ツイスターを使用してランダムに並び替え
    mt19937 mt(static_cast<unsigned int>(time(0)));
    random_shuffle_for_engine(v.begin(), v.end(), mt);

    return 0;
}


※私が作ったRange STLアルゴリズムを使用して以下のように実装してもいい

#include <shand/algorithm.hpp> // shand::random_shuffle

template <class Container, class Engine>
inline void random_shuffle_for_engine(Container& c, Engine& engine)
{
    random_number_generator<Engine> gen(engine);
    shand::random_shuffle(c, gen);
}
vector<int> v;
mt19937 mt(static_cast<unsigned int>(time(0)));
random_shuffle_for_engine(v, mt);

※一時オブジェクトを非const参照で渡していたのを修正
※random_number_generatorを簡単に作りすぎたので後ほど修正してエントリ書きます