//版本一:使用内部的随机数生成器 template<class RandomAccessIterator> void random_shuffle( RandomAccessIterator _first, RandomAccessIterator _last ) { __STL_REQUIRES(_RandomAccessIter, _Mutable_RandomAccessIterator); if (__first == __last) return; for (_RandomAccessIter __i = __first + 1; __i != __last; ++__i) iter_swap(__i, __first + __random_number((__i - __first) + 1)); } //版本二:是使用一个会产生随机数的仿函数 template<class RandomAccessIterator, class RandomNumberGenerator> void random_shuffle( RandomAccessIterator _first, RandomAccessIterator _last, RandomNumberGenerator& gen ) { __STL_REQUIRES(_RandomAccessIter, _Mutable_RandomAccessIterator); if (__first == __last) return; for (_RandomAccessIter __i = __first + 1; __i != __last; ++__i) iter_swap(__i, __first + __rand((__i - __first) + 1)); }
随机重排[first,last)中的数据,有N!中可能,N=last-first,此算法会产生一种均匀分布,任何特定排列顺序被选中的几率为1/N!,版本二是一种特别的function object,当被引数传进来,传递方式是by reference,而不是by value,因为RandomNumberGenerator的重要特点是具有局部状态,每次被调用时被改变。
使用乱数时,能够明白设定乱数产生器的种子是非常重要的,如果这对程序重要,则使用第二个版本。
#include <iostream> #include <vector> #include <algorithm> #include <cstdio> #include <ctime> using namespace std; class F { public: ptrdiff_t operator()(ptrdiff_t max) { srand((unsigned)time(NULL)); int _rand=static_cast<int>(rand()/static_cast<int>(RAND_MAX)); return static_cast<ptrdiff_t>(_rand*max); } }; int main() { vector<int> v{1,2,3,4,5,6}; random_shuffle(v.begin(),v.end(),F()); for_each(v.begin(),v.end(),[](int i) { cout<<i<<" "; }); cout<<endl; return 0; }
random_sample
template <class InputerIterator,class RandomAccessIterator> RandomAccessIterator random_sample(InputerIterator first,InputIterator last,RandomAccessIterator ofirst,RandomAccessIterator olast); template <class InputerIterator,class RandomAccessIterator> RandomAccessIterator random_sample(InputerIterator first,InputIterator last,RandomAccessIterator ofirst,RandomAccessIterator olast,RandomNumberGenerator &rand);
- 随机的将[first,last)中的一个取样结果复制到[ofirst,olast)中,它会复制n个元素,n为min(last-first,olast-ofirst),Input range中的每个元素至多在Output range中出现一次,该结果以均匀方式选出
- 返回值为ofirst+n
- 对于N个元素,忽略元素顺序,欲选出n个元素,共有N!/(n!(N-n)!)中方法,本算法会产生均匀分布的结果,任何特定的元素被选出的几率为n/N,任何特定取样(不考虑元素顺序)几率为n!(N-n)!/N!
- 第一个版本用内部自定义的乱数产生器,第二个版本用自己定义的function object的乱数产生器
- Input range必须是Forward Iterator,Output range必须是RandomAccessIterator,所以Output range中元素的性对顺序不一定会与Input ragne中的顺序相同
random_sample_n
template <class InputerIterator,class OutputerIterator,class Distance> OutputerIterator random_sample_n(InputerIterator first,InputIterator last,OutputerIterator out,Distance n); template <class InputerIterator,class OutputerIterator,class Distance,class RandomNumberGenerator> OutputerIterator random_sample_n(InputerIterator first,InputIterator last,OutputerIterator out,Distance n,RandomNumberGenerator &rand);
- 从[first,last)中随机的复制元素到[out,out+n)中,他将复制m个元素,此处m为min(last-first,n),Input range中的每个元素至多在Output range中出现一次,该结果以均匀方式选出
- 返回值为out+m
- Input range必须是Forward Iterator,Output range必须是 Output Iterator,所以会保证两个容器中的相对顺序相同