我该怎样shuffle呢

博客围绕STL的mutating algorithm展开,重点探讨random_shuffle方法。作者试验该方法时发现每次运行产生的随机序列相同,经深入debug,发现是未改变随机数种子所致。为使结果不同,作者重写函数,后发现调用前调用srand方法即可。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        在STL的Algorithm中有着这样的一种算法:mutating algorithm,这一类算法的主要作用是改变Sequence Container中元素的顺序。而改变元素顺序的方法有好几个,如将元素反序(reverse),将元素位置循环旋转(rotate)等,而最吸引我的就是能够产生随机序列的方法了(random_shuffle)。
        于是,我写了一段代码是试验一下这个方法:

None.gif#include <iostream>
None.gif#include 
<algorithm>
None.gif#include 
<iterator>
None.gif#include 
<vector>
None.gif
None.gif
using namespace std;
None.gif
None.gif
void main()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif  vector
<int> v1(10);
InBlock.gif  
for(int j = 0; j < v1.size(); ++j)
InBlock.gif    v1[ j ] 
= j;
InBlock.gif  ostream_iterator
<int> iter(cout, " ");
InBlock.gif  copy(v1.begin(), v1.end(), iter);
InBlock.gif  cout 
<< " ";
InBlock.gif  random_shuffle(v1.begin(), v1.end());
InBlock.gif  copy(v1.begin(), v1.end(), iter);
InBlock.gif  cout 
<< " ";
ExpandedBlockEnd.gif}

None.gif
None.gif

        当我第一次执行的时候,哇,果然次序挺乱的哦。结果如下:

None.gif0 1 2 3 4 5 6 7 8 9
None.gif
4 3 0 2 6 7 8 9 5 1

        然后我满心欢喜的将程序再执行了一遍,咦,怎么那么像原来的序列呢?我反复运行了几次,结果让我很沮丧,因为产生的随机序列是一样的。为什么会这样呢?只能深入到random_shuffle方法里面去瞧瞧了,于是我又开始debug之旅。
        在STL中的random-shuffle函数的实现是这样的:

None.giftemplate<class _RI> 
None.gifinline 
void random_shuffle(_RI _F, _RI _L)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif  
if (_F != _L)
InBlock.gif  _Random_shuffle(_F, _L, _Dist_type(_F)); 
ExpandedBlockEnd.gif}

None.gif
None.giftemplate
<class _RI, class _Pd> 
None.gifinline 
void _Random_shuffle(_RI _F, _RI _L, _Pd *)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif  
const int _RBITS = 15;
InBlock.gif  
const int _RMAX = (1U << _RBITS) - 1;
InBlock.gif  _RI _X 
= _F;
InBlock.gif  
for (_Pd _D = 1++_X != _L; ++_D)
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif    unsigned 
long _Rm = _RMAX;
InBlock.gif    unsigned 
long _Rn = rand() & _RMAX;
InBlock.gif    
for (; _Rm < _D && _Rm != ~0UL;
InBlock.gif     _Rm 
= _Rm << _RBITS | _RMAX)
InBlock.gif     _Rn 
= _Rn << _RBITS | _RMAX;
InBlock.gif     iter_swap(_X, _F 
+ _Pd(_Rn % _D)); 
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif
None.gif

        在random_shuffle的两个参数的版本中,我们可以发现这样的一个函数:_Dist_type(_F)。而在iterator类中,我看到了这样的代码:

None.giftemplate<class _Ty> 
None.gifinline ptrdiff_t 
*_Dist_type(const _Ty *)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{return ((ptrdiff_t *)0); }
None.gif

        在STDDEF.H文件中,我也找到ptrdiff的定义:typedef int ptrdiff_t。那么这个函数到底做了什么呢?不就是返回了一个 int *吗?而且值为00000000。更要命的是,传递进去之后,也没有地方使用啊,整个函数就在for循环出出现了_Pd,那么在这样的一段代码中,_Pd起到了怎样的作用呢?我觉得一点用处都没有。接下来的代码,由于在运行的时候,都没有改变通过srand改变随机数种子的话,得到的_Rn是恒定的,所以每次运行的结果都一样就不难理解了。现在我是知道了为什么得到的随机序列是一样的了,可是这个函数为什么要设计成这样呢?我能想到的就是为了随机序列能够被追溯吧。
    为了能够让每次运行的结果都不一样,于是我重写了这个函数:

None.giftemplate <typename T> 
None.gifinline 
void shuffle(T first, T last)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif  
const int _RBITS = 15;
InBlock.gif  
const int _RMAX = (1U << _RBITS) - 1;
InBlock.gif  T temp 
= first;
InBlock.gif  srand((unsigned)time(NULL));
InBlock.gif  
for (int i = 1++temp != last; ++i)
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif
InBlock.gif    unsigned 
long _Rm = _RMAX;
InBlock.gif    unsigned 
long _Rn = rand() & _RMAX;
InBlock.gif    
for (; _Rm < i && _Rm != ~0UL;_Rm = _Rm << _RBITS | _RMAX)
InBlock.gif       _Rn 
= _Rn << _RBITS | _RMAX;
InBlock.gif    iter_swap(temp, first 
+ int(_Rn % i)); 
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif

        其实也没有改变什么,只是增加srand函数去改变随机种子并且去掉了对_Dist_type函数的调用而已。当我写到这里,突然间想到了是否可以不重写方法呢?只要在调用random_shuffle函数之前调用srand方法不就行了吗?试了一下,果然成功了。哇,太笨了。What a shame!
        说实在的,我对那个_Pd还是有点云里雾里的,还恳请各位大侠指点一二了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值