20

私は2つのベクトルを持っています:

vector1 = [1 2 3 4 5 6 7 8 9]

vector2 = [1 2 3 4 5 6 7 8 9]

random_shuffleを使用して両方をシャッフルするときに、同じ対応する順序でシャッフルする必要があることを確認したいと思います。例えば:

シャッフル後の出力は次のようになります。

vector1 = [1 9 3 4 2 7 8 5 6]

vector2 = [1 9 3 4 2 7 8 5 6]

しかし、私は次のような出力を得ています:

vector1 = [5 1 7 4 2 3 9 8 6]

vector2 = [3 4 1 9 8 2 5 7 6]

私のコードは次のとおりです。

int main () 
{
  std::srand ( unsigned ( std::time(0) ) );
  std::vector<int> vector1, vector2;

  // set some values:
  for (int i=1; i<10; ++i)
  {
    vector1.push_back(i);
    vector2.push_back(i);
  }

  // using built-in random generator:
  std::random_shuffle ( vector1.begin(), vector1.end() );
  std::random_shuffle ( vector2.begin(), vector2.end() );

  // print out content:
  std::cout << "vector1 contains:";
  for ( std::vector<int>::iterator it1 = vector1.begin(); it1 != vector1.end(); ++it1 )
    std::cout << ' ' << *it1;

  std::cout << '\n';
  std::cout << '\n';

  std::cout << "vector2 contains:";
  for ( std::vector<int>::iterator it2 = vector2.begin(); it2 != vector2.end(); ++it2 )
    std::cout << ' ' << *it2;

  std::cout << '\n';
  std::cout << '\n';

  return 0;
}

EDITこれは、私が実装しようとした例です。実際には、画像の 1 つのベクトルと対応するラベルの 1 つのベクトルがあります。同じようにシャッフルする必要があります。どなたか助けてください……どうもありがとうございました!!

4

8 に答える 8

30

ベクトル自体をシャッフルする代わりに、インデックスのベクトルを他のベクトルにシャッフルします。両方に同じインデックスを使用するため、同じ順序であることが保証されます。

std::vector<int> indexes;
indexes.reserve(vector1.size());
for (int i = 0; i < vector1.size(); ++i)
    indexes.push_back(i);
std::random_shuffle(indexes.begin(), indexes.end());

std::cout << "vector1 contains:";
for ( std::vector<int>::iterator it1 = indexes.begin(); it1 != indexes.end(); ++it1 )
    std::cout << ' ' << vector1[*it1];
于 2013-06-06T17:07:34.047 に答える
17

への両方の呼び出しに同じシードを使用していることを確認してくださいrandom_shuffle()

auto seed = unsigned ( std::time(0) );

// ...

std::srand ( seed );
std::random_shuffle ( vector1.begin(), vector1.end() );

std::srand ( seed );
std::random_shuffle ( vector2.begin(), vector2.end() );

ただし、標準ではrandom_shuffle()、関数を使用しrand()てランダム順列を生成する必要があることを指定していないことに注意してください。これは実装定義です。したがって、を使用しない実装srand()の結果には影響しません。random_shuffle()rand()

C++11 標準のパラグラフ 25.3.12/4 では、次のようにrandom_shuffle()指定されています。

備考: これらの関数の実装で乱数を使用する場合、実装では次の乱数ソースを使用する必要があります。

関数の最初の形式の乱数の基になるソースは実装定義です。実装でrand、標準 C ライブラリの関数を使用できます。[...]

したがって、確実に移植可能なコードを作成したい場合random_shuffle()は、乱数ジェネレーターを 3 番目の引数として受け入れるバージョンの を使用して、シード処理を制御できるようにします。

于 2013-06-06T16:56:27.523 に答える
4

逆参照された場合、対応するベクトルの要素の参照への std::tuple を返すランダム アクセス イテレータを作成できます。そのため、それらをその場でシャッフルできます。または、ブーストバージョンを見てください。したがって、次のようになります。

std::random_shuffle(
  boost::make_zip_iterator(
    boost::make_tuple(vector1.begin(), vector2.begin())
  ),
  boost::make_zip_iterator(
    boost::make_tuple(vector1.end(), vector2.end()
  ),

);

これは、データをその場でシャッフルし、3つ以上のベクトルで機能し、何が機能するかを知っていれば自己文書化make_zip_iteratorします. もちろん、シャッフルを 2 回行ったり、3 番目のベクトルを使用したりするよりも高速である必要があります。

于 2013-06-06T17:16:15.200 に答える
2

シャッフルするたびに、疑似乱数ジェネレーターに再現可能な値をシードします。

std::srand ( 42 );
std::random_shuffle ( vector1.begin(), vector1.end() );
std::srand ( 42 );
std::random_shuffle ( vector2.begin(), vector2.end() );
于 2013-06-06T16:55:24.007 に答える
2

両方が同じ順序でなければならない場合、なぜそれらは別々のベクトルなのですか? 論理的な解決策は次のようになります。

struct ImageData
{
    Image myImage;
    std::string myLabel;
    //  ...
};

ImageData次に、シャッフルする単一のベクトルを取得します。

于 2013-06-06T17:21:16.870 に答える
0

残念ながら、srand を使用すると、内部のシード値が変更されます。つまり、次の乱数はあらかじめ決まっています。そして、最初の決定:

std::srand ( 42 );
std::random_shuffle ( vector1.begin(), vector1.end() );
std::srand ( 42 );
std::random_shuffle ( vector2.begin(), vector2.end() );
std::srand ( unsigned ( std::time(0) ) );
// Post-code.

郵便番号のランドを保存します。

2 番目の決定 - これは Mark Ransom の解決策です - std::srand をまったく呼び出しません (そして、パフォーマンスが高いことに気付きました)。

于 2013-06-06T17:22:17.167 に答える
-1

独自のシャッフルを作成してみませんか。

for( size_t i = 0 ; i < numitems; ++i )
{
    size_t next = random() % numitems ;
    swap( v1[i], v1[next] );
    swap( v2[i], v2[next] );
}
于 2013-06-06T17:08:41.973 に答える