随机采样具有固定数量的零的数组

时间:2014-04-29 11:28:46

标签: c performance algorithm math

我有优化的代码来随机采样包含-1s,0s和1s的数组,概率为1 / 4,1 / 2,1 / 4。它看起来像

#define n (12)
unsigned int x,y=34353,z=57768,w=1564; //PRNG seeds
/* xorshift PRNG
 * Taken from https://en.wikipedia.org/wiki/Xorshift#Example_implementation
 * Used under CC-By-SA */
u_int32_myRand() {
    unsigned int t;
    t = x ^ (x << 11);
    x = y; y = z; z = w;
    return w = w ^ (w >> 19) ^ t ^ (t >> 8);
}

x=(int)time(NULL); //seed PRNG
unsigned int k
int F[n];
for(k=0; k<n; k++) {
      F[k]=(1-(myRand()&3))%2;  
    }

如何修改它以便它只返回其中只有n / 3个零的数组并且仍然快速?

3 个答案:

答案 0 :(得分:3)

最简单的方法是用n / 3个零填充数组的第一部分。然后根据需要添加1和-1。然后,执行Fisher-Yates shuffle随机化数组。

尝试“随机分配n / 3个零”的问题是您难以防止重叠。也就是说,如果你想在99的数组中放置33个零,你不能只选择33个随机索引,因为你可能会得到重复。所以你最终会得到阵列中少于33个零。

至于性能,这几乎与您当前的示例一样快。它只需要在阵列上额外传递。生成的随机数的数量是相同的。

答案 1 :(得分:2)

分两步进行:

  1. 在您的数组上随机分配n/3个零,并将其余部分设置为1
  2. 为剩余的符号分配一个随机符号,以获得所需的-1 / + 1。
  3. 示例代码:

    int F[n];
    // fill with 1
    for(k=0; k<n; k++) {
        F[k] = 1;
    }
    // distribute n/3 zeros
    for(k=0; k<n/3; k++) {
        // find a location which does not have a 0 yet
        int i;
        do {
            i = myRand() % n;
        } while(F[i] == 0);
        F[i] = 0;
    }
    // change remaining (non zero) to -1 with 50% probability
    for(k=0; k<n; k++) {
        if(F[k] && myRand()%2) F[k] = -1;
    }
    

    这个运行时间大约为2.4 n,但我认为你不会比这更快。

    对于n / 3个零的情况,第二个for循环中的while循环平均执行大约1.2倍。


    <强>注:

    如果成功概率足够高,第二个for循环中使用的试验和错误效果很好。 p概率所需的平均试验次数为1 / p。

    在我们的情况下(n / 3个零),找到好位置(即最后一个零)的最差概率是2/3,因此平均1.5次迭代。要找到所有n / 3个零的位置,平均需要0.2 * n次迭代。

    平均运行时间可以计算为-log(1-a),其中a是您要分发的零的百分比(在您的情况下为a = 1/3)。

    更多示例:如果您想要分发2/3 * n个零,则需要1.1 * n次迭代。对于0.99 * n个零,它已经是4.6 * n次迭代。

    全部平均。在最糟糕的情况下,它需要永远。


    如果您需要运行时保证,通过实现实际采样而不进行重选可能会更好,即填充具有所有可能索引的容器,将随机元素作为索引进行采样并将其从容器中删除。但这可能有大约O(n * log(n))的运行时间。因此,它适用于小n或大百分比的零。

答案 2 :(得分:1)

这是一个简单的算法:

  1. 将所需数量的零(n/3)放入输出数组
  2. 对于其他地方,请1-1概率为1/2
  3. Shuffle the array
  4. 然而:

      

    ...包含-1s,0和1的数组,概率为1 / 4,1 / 2,1 / 4

    这是否意味着数组中确实存在n/4 1&#39;让我们假设它没有。然后:

    • 计算数组中1&#39; s(a)和-1&#39; s(b)的数量
    • 1的概率为a/(a+b);在上述算法中使用它而不是1/2

    注意:如果您的输入数组中只有零或根本没有零,则无法使用n/3零进行采样!