在各種程序語言中都提供了將容器元素隨機排序的shuffle方法,c++也不例外。
不過c++將shuffle放在了<algorithm>中而不是像其他語言一樣在random里,同時c++17刪除了原先的random_shuffle新的程序應該使用c++11添加進去的std::shuffle。其中一個好處是新的函數在可以自定義隨機數生成方法的同時保證了更好的安全性。
先來看下新函數的原型:
template< class RandomIt, class URBG >
void shuffle( RandomIt first, RandomIt last, URBG&& g );
其中first和last指定需要隨機排序的范圍,g是一個“UniformRandomBitGenerator”,就是一個可以產生規定范圍內的隨機數的可調用對象。
所以g可以是std::random_device或者像std::default_random_engine這樣的隨機數引擎,也可以是std::mt19937這樣的標准庫提供的隨機數生成器的對象,它們都在<random>中。
shuffle調用后目標容器內的元素排列順序會被隨機打亂,我們看個例子。
首先是兩個幫助函數,避免做一些重復勞動:
// 幫助函數,打印vector的內容
template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v)
{
os << "{ ";
for (const auto &i: v) {
os << i << ", ";
}
os << "}";
return os;
}
// 幫助函數,生成一個符合UniformRandomBitGenerator要求的隨機數生成器;
// std::random_device雖然符合要求但是只適合於生成seed及安全要求較高的場合,因為速度可能很慢。
// 所以我們選擇std::mt19937算法,你可以自己選擇其他合適的算法
auto get_URBG()
{
std::random_device rd;
// 使用random_device生成seed
std::mt19937 g(rd());
return g;
}
然后我們分別打亂一個std::vector<int>和std::vector<std::string>容器內元素的排列順序:
// 隨機排序容器內元素,打印隨機排序前和隨機排序后的容器內容
template <typename T>
void shuffle_container(std::vector<T> &container)
{
std::cout << "before shuffle: " << container << std::endl;
std::shuffle(container.begin(), container.end(), get_URBG());
std::cout << "after shuffle: " << container << std::endl;
}
int main()
{
std::vector<int> ivec{1,2,3,4,5};
shuffle_container(ivec);
// 分割線
std::cout << std::string(40, '-') << std::endl;
std::vector<std::string> svec{"a", "b", "c", "d", "e", "f", "g"};
shuffle_container(svec);
}
我們編譯寫好的程序,然后運行:

可以看到元素都已經被隨機排序了。
