我有两个向量:
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;
}
编辑这是我尝试实施的示例案例。在实践中,我有一个图像矢量和一个相应标签的矢量。我需要他们以同样的方式洗牌。请有人帮忙...... 非常感谢!!
答案 0 :(得分:29)
不是将矢量自身混洗,而是将索引矢量混合到其他矢量中。由于您将为两者使用相同的索引,因此保证它们的顺序相同。
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];
答案 1 :(得分:15)
确保对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()
的实施的结果。
random_shuffle()
上C ++ 11标准的第25.3.12 / 4段规定:
备注:如果这些函数的实现使用随机数,那么 实施应使用以下随机来源:
函数的第一种形式的随机数的基础源是实现定义的。 实现可能使用标准C库中的
rand
函数。 [...]
因此,如果您想确保编写可移植代码,请使用接受随机数生成器作为第三个参数的random_shuffle()
版本,以便您可以控制播种。
答案 2 :(得分:7)
正如其他人已经表明的那样,使用相同的种子重新播种应该允许您多次复制相同的shuffle。但是,如果您可以使用C ++ 11,我建议您不使用srand()
和random_shuffle()
来实现此功能。相反,您应该将<random>
库与std::shuffle
一起使用。
首先,如果可能,应避免使用rand
。除了它通常不是一个非常好的pRNG之外,由于共享状态,它还存在线程安全性问题。 <random>
库通过让程序员明确控制pRNG状态并提供几个保证性能,大小和质量特性的选项来解决这两个问题。
其次,random_shuffle
实际上并未指定使用rand
,因此理论上使用srand
重新播种不具备您想要的效果是合法的。要使用random_shuffle
获得有保证的结果,您必须编写自己的生成器。转而shuffle
修复了这一点,因为您可以直接使用标准引擎。
#include <algorithm> // shuffle, copy
#include <iostream> // cout
#include <iterator> // begin, end, ostream_iterator
#include <numeric> // iota
#include <random> // default_random_engine, random_device
#include <vector> // vector
int main() {
std::vector<int> v1(10);
std::iota(begin(v1), end(v1), 1);
auto v2 = v1;
std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
// create two random engines with the same state
std::mt19937 eng1(seed);
auto eng2 = eng1;
std::shuffle(begin(v1), end(v1), eng1);
std::shuffle(begin(v2), end(v2), eng2);
std::copy(begin(v1), end(v1), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n\n";
std::copy(begin(v2), end(v2), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n\n";
}
答案 3 :(得分:3)
你可以创建一个随机访问迭代器,如果它的dereferenced将std :: tuple返回给相应向量元素的引用。所以你可以把它们推到原地。或者你看看the boost version。 所以看起来应该是这样的:
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()
),
);
这会将您的数据放在适当位置,使用两个以上的向量,如果您知道make_zip_iterator
的作用,则自我记录。当然它应该比洗牌两次更快或使用第三个向量。
答案 4 :(得分:2)
在每次随机播放之前,使用可重现的值为伪随机数生成器播种。
std::srand ( 42 );
std::random_shuffle ( vector1.begin(), vector1.end() );
std::srand ( 42 );
std::random_shuffle ( vector2.begin(), vector2.end() );
答案 5 :(得分:2)
如果两者必须具有相同的顺序,为什么它们是分开的 引导?逻辑解决方案如下:
struct ImageData
{
Image myImage;
std::string myLabel;
// ...
};
然后你有一个ImageData
的向量,你可以随机播放。
答案 6 :(得分: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.
为后置代码保存rand。
第二个决定 - 它是Mark Ransom解决方案 - 它根本不会调用std :: srand(而且,我只是注意到它具有更高的性能)。
答案 7 :(得分:-1)
你为什么不写自己的shuffle:
for( size_t i = 0 ; i < numitems; ++i )
{
size_t next = random() % numitems ;
swap( v1[i], v1[next] );
swap( v2[i], v2[next] );
}