Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/webpack/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 减少随机洗牌算法中rand的调用次数_C++ - Fatal编程技术网

C++ 减少随机洗牌算法中rand的调用次数

C++ 减少随机洗牌算法中rand的调用次数,c++,C++,我已经实现了Fisher-Yates算法来随机洗牌我的数组。 目前,我正在调用rand()函数8次。我的问题是:我怎么能只调用rand()函数6次呢。 以下是我的实现: class numbers{ private: static int indexCount; vector <vector <int> > list; vector<int> temp; public: void swap (int *a, int *b)

我已经实现了Fisher-Yates算法来随机洗牌我的数组。 目前,我正在调用
rand()
函数8次。我的问题是:我怎么能只调用
rand()
函数6次呢。 以下是我的实现:

class numbers{
private:
    static int indexCount;
    vector <vector <int> > list;
    vector<int> temp;

public:

    void swap (int *a, int *b)  
    {  
      int temp = *a;  
      *a = *b;  
      *b = temp;  
    }  

    int randomize (int arr[], int n)  
    {  
      RandomCount=0;

      for (int i = n - 1; i > 0; i--)  
      {  
          int j = rand() % (i + 1);  
          RandomCount++;
          swap(&arr[i], &arr[j]);  
      }
    }
类号{
私人:
静态int索引计数;
向量表;
向量温度;
公众:
无效交换(int*a,int*b)
{  
int temp=*a;
*a=*b;
*b=温度;
}  
int随机化(int arr[],int n)
{  
随机计数=0;
对于(int i=n-1;i>0;i--)
{  
int j=rand()%(i+1);
随机计数++;
掉期交易(&arr[i]、&arr[j]);
}
}
我试图计算调用
rand()
函数的次数,由于循环的原因,调用次数为8次,但我试图将这个数字降到6次,同时仍然对数组进行随机化


数组包含值
{1,2,3,4,5,6,0,0,0}
。我注意到,因为我的数组中有三个0,所以我可以在不使用
rand()
函数的情况下交换它们。但是,我不确定该怎么做。

首先,我要说
rand()
通常不被视为随机数生成器–它通常不是一个很好的生成器,依赖于隐藏的全局状态,并且使用
rand()%n
会引入偏差。由于C++11,最好使用
中提供的随机数生成器

但是,按照您的示例,我假设您的限制是对
rand()
的六次调用,而不一定是六个随机数。因此,我们可以利用
rand()
rand_MAX
,至少
32767
)的范围比您希望生成的数字大得多的事实(在本例中,最多为
9
)。那么,我们为什么不一次生成两个数字呢

例如,如果我们需要在
A=[0,4)
B=[0,3)
范围内获得两个随机数,我们可以在
X=[0,4*3)=[0,12)
范围内生成一个随机数。然后,我们可以将
A=X%4=[0,4)
B=X/4=[0,3)
作为均匀分布的随机变量

这样做允许我们对
rand()
的每次调用执行两个步骤。对于长度为9的数组,我们有
9=4*2+1
,因此我们只需5次调用
rand()

转换循环:

RandomCount=0;
int i=n-1;
//如果数组长度为奇数,首先执行剩余元素
如果(n%2){
//(这是一种生成随机数的糟糕方法,但我会坚持使用)
int j=rand()%(i+1);
随机计数++;
掉期交易(&arr[i]、&arr[j]);
我--;
}
//现在做剩下的,一次两个
对于(;i>0;i-=2)
{  
//得到我们的两个随机数
int r=rand()%((i+1)*i);
随机计数++;
int a=r%(i+1);//在[0,i+1]中的数字
int b=r/(i+1);//在[0,i]中的数字
//做两次互换
掉期(&arr[i]、&arr[a]);
掉期交易(&arr[i-1]、&arr[b]);
}
使用更多的随机数可能会做得更好。但是,请注意,这只适用于足够小的
n
:如果
n*(n-1)>RAND_MAX
,那么您将遇到问题,因为您将无法生成足够大的随机数


来解释为什么分裂的工作,让我们考虑两个值。假设我们想要在范围<代码> A=(0,X)< /代码>和<代码> B=(0,Y)< /代码>。我们在一个范围内生成一个编号:代码> r=(0,x*y)< /代码> < /p>

  • 我们可以说,
    A=R%Y=[0,Y)
    %
    运算符是模运算符,或者余数(对于正数)运算符。也就是说,当除以
    Y
    时,我们还有多少剩余?可能的值是0的所有数字(
    Y
    等分)通过
    Y-1
    。此外,由于
    R
    中的最小数为0,最大数小于
    Y
    的倍数,因此分布均匀
  • 我们可以说
    B=R/Y=[0,X)
    。对于整数楼层分割,从
    0
    Y-1
    R
    中的任何数字映射到
    B
    中的
    0
    ,从
    Y
    2Y-1
    的任何数字映射到
    B
    中的
    1
    ,依此类推。这将上升到我们的最大值
    XY-1
    ,映射到
    p准确地说

你可以把它看作是一个二维的填充数字表,有
X
行和
Y
列。
R
在表中选择一个随机索引。当你取
R/Y
时,你得到哪一行,当你取
R%Y
时,你得到哪一列。

首先,我要说
rand()
通常不被视为随机数生成器–它通常不是一个很好的生成器,依赖于隐藏的全局状态,并且使用
rand()%n
会引入偏差。由于C++11,最好使用
中提供的随机数生成器

但是,按照您的示例,我假设您的限制是对
rand()
的六次调用,而不一定是六个随机数。因此,我们可以利用
rand()
rand_MAX
,至少
32767
)的范围比您希望生成的数字大得多的事实(在本例中,最多为
9
)。那么,我们为什么不一次生成两个数字呢

例如,如果我们需要在
A=[0,4)
B=[0,3)
范围内获得两个随机数,我们可以在
X=[0,4*3)=[0,12)
范围内生成一个随机数。然后,我们可以将
A=X%4=[0,4)
B=X/4=[0,3)
作为均匀分布的随机变量

这样做可以让我们做两件事
[ r00 | r01 | ... | r13 | r14 ] <-- lower 15 bits from first call to rand()
[ r15 | r16 | ... | r28 | r29 ] <-- lower 15 bits from second call to rand()
 o
 o
 o
[ r75 | r76 | ... | r88 | r89 ] <-- lower 15 bits from sixth call to rand()
Iteration | Choices | Bits Required
----------+---------+--------------
        0 |       9 | about   3.17
----------+---------+--------------
        1 |       8 | exactly 3
----------+---------+--------------
        2 |       7 | about   2.81
----------+---------+--------------
        3 |       6 | about   2.58
----------+---------+--------------
        4 |       5 | about   2.32
----------+---------+--------------
        5 |       4 | exactly 2
----------+---------+--------------
        6 |       3 | about   1.58
----------+---------+--------------
        7 |       2 | exactly 1
----------+---------+--------------
        8 |       1 | exactly 0
// changed return type to void since this doesn't return anything
void randomize (int arr[], int n)
{
  // generate our bit pool for uniform distributions of size 2^n
  int integral_rand_pool = rand();

  for (int i = n - 1; i > 0; i--)  
  {
      int j;
      if (i == 7)
      {
        // need 3 bits of entropy
        j = integral_rand_pool & 0x07;
        integral_rand_pool = integral_rand_pool >> 3;
      }
      else if (i == 3)
      {
        // need 2 bits of entropy
        j = integral_rand_pool & 0x03;
        integral_rand_pool = integral_rand_pool >> 2;
      }
      else if (i == 1)
      {
        // only need 1 bit of entropy
        j = integral_rand_pool & 0x01;
        integral_rand_pool = integral_rand_pool >> 1;
      }
      else
      {
        // need a non-integral number of bits. Just grab 15 from rand()
        j = rand() % (i + 1);
      }  
      swap(&arr[i], &arr[j]);  
  }
}