パハットノート

※当サイトではGoogleアドセンス広告を利用しています

C++ 乱数配列の作成





乱数の生成

参考

こちらのサイトを参考にしました。
色々な乱数が紹介されていましたが、範囲指定の一様乱数の場合は、std::uniform_int_distribution使えば良さそうなので、以下ではこれを使っていきます。
qiita.com


ソースコード

  • distの第1引数にminを、第2引数にmaxを設定します。こうすることで、乱数の範囲をmin~maxに制限できます。
  • 注意としては、maxはその数値自身も含む点だと思います。他の言語では、min~max-1が生成される場合もある。
#include <iostream>
#include <random>

int main()
{
    //今回は0~3の範囲で乱数を生成
    std::mt19937 mt{ std::random_device{}() };
    std::uniform_int_distribution<int> dist(1, 3);

    //適当に5回ほど生成
    for (int i = 0; i < 5; i++)
    {
        std::cout << "i = " << i << ", dist(mt) = " << dist(mt) << std::endl;
    }
}



実行結果

i = 0, dist(mt) = 2
i = 1, dist(mt) = 2
i = 2, dist(mt) = 1
i = 3, dist(mt) = 3
i = 4, dist(mt) = 3





乱数配列の生成

乱数配列の生成は先ほどの様にfor文で回して、vectorにでも格納してしまえばよさそうです。

#include <iostream>
#include <random>

//重複なしの、乱数配列を返す
std::vector<int> RandomVec1(int size, int min, int max) {

    //配列の宣言
    std::vector<int> v(size, 0);

    //乱数生成のための
    std::mt19937 mt{ std::random_device{}() };
    std::uniform_int_distribution<int> dist(min, max);

    //for文で重複がないかチェックしながら乱数を生成
    for (int i = 0; i < v.size(); i++) {
        v[i] = dist(mt);
    }

    return v;

}

int main(){
    //長さ5で、-2~2の乱数を格納する配列を生成
    std::vector<int> v1 = RandomVec1(5, -2, 2);

    //表示
    for (int i = 0; i < v1.size(); i++) {
        std::cout << "v1[" << i << "] = " << v1[i] << std::endl;
    }
}



実行結果

v1[0] = -2
v1[1] = 0
v1[2] = 0
v1[3] = 2
v1[4] = -1





重複なしの乱数配列の生成

重複なしというのがちょっと面倒くさそうです。
と思っていたのですが、std::countという関数を使えば、vectorに指定した要素が含まれているかを確認できるみたいです。
www.techiedelight.com


ソースコード

#include <iostream>
#include <random>
#include <algorithm>

//重複なしの、乱数配列を返す
std::vector<int> RandomVec2(int size, int min, int max) {

    //max-min+1 < sizeだと重複なしの乱数配列の生成が不可なので、exitする
    if (max - min + 1 < size) {
        exit(1234);
    }

    //配列の宣言
    std::vector<int> v(0);

    //乱数生成のための
    std::mt19937 mt{ std::random_device{}() };
    std::uniform_int_distribution<int> dist(min, max);

    //for文で重複がないかチェックしながら乱数を生成
    for (int i = 0; i < size; i++) {

        while (true) {

            //乱数生成
            int r = dist(mt);

            //rがdistに含まれていなかったら、追加してから、whileループを抜ける
            if (std::count(v.begin(), v.end(), r) == 0) {
                v.push_back(r);
                break;
            }
        }
    }

    return v;

}

int main(){
    //長さ5で、-2~2の乱数を格納する配列を生成
    std::vector<int> v1 = RandomVec2(5, -2, 2);

    //表示
    for (int i = 0; i < v1.size(); i++) {
        std::cout << "v1[" << i << "] = " << v1[i] << std::endl;
    }

    //こっちは、max-min+1 < sizeになるため実行されない
    std::vector<int> v2 = RandomVec2(5, 0, 2);

    //表示(実行されない)
    for (int i = 0; i < v1.size(); i++) {
        std::cout << "v2[" << i << "] = " << v2[i] << std::endl;
    }
}



実行結果

先ほどの違って、重複がないことが確認できます。

v1[0] = 1
v1[1] = 2
v1[2] = -2
v1[3] = 0
v1[4] = -1





選択肢から作成

概要

選択肢をvectorで与えておく方法です。
文字列などで乱数を生成するときに使えると思います。


ソースコード

#include <iostream>
#include <random>
#include <string>

//選択肢から乱数配列を返す
template<class T>
std::vector<T> RandomVec3(int size, std::vector<T> choices) {

    //配列の宣言
    std::vector<T> v(size);

    //乱数生成のための
    std::mt19937 mt{ std::random_device{}() };
    std::uniform_int_distribution<int> dist(0, choices.size() - 1);

    //for文で重複がないかチェックしながら乱数を生成
    for (int i = 0; i < v.size(); i++) {
        v[i] = choices[dist(mt)];
    }

    return v;

}

int main(){
    //選択肢
    std::vector<std::string> fruits = { "apple", "banana", "lemon" };

    //長さ5で、-2~2の乱数を格納する配列を生成
    std::vector<std::string> v1 = RandomVec3<std::string>(6, fruits);

    //表示
    for (int i = 0; i < v1.size(); i++) {
        std::cout << "v1[" << i << "] = " << v1[i] << std::endl;
    }
}



実行結果

v1[0] = banana
v1[1] = apple
v1[2] = lemon
v1[3] = apple
v1[4] = lemon
v1[5] = apple