如何在不缓存到数组的情况下采样0、1,...,n-1中的k个随机数

时间:2018-07-20 14:58:05

标签: c++ random

我想在0、1、2,...,n-1中采样k个不同的(不替换)随机数。

在我看来,我在网上可以找到的大多数解决方案都需要一个存储所有数字的数组,然后以某种方式将其洗牌。但是,它占用O(n)空间。我想知道C ++中是否有任何方法可以不生成数组。

1 个答案:

答案 0 :(得分:2)

当然

它称为Reservoir Sampling。基本上,您假装从流中获取值0、1、2,...,n-1,对随机数进行采样并将其与存储库交换。

曾经是伪代码,对其进行了调试,现在它应该可以正常工作

#include <iostream>
#include <random>
#include <vector>

static int N = 0;
static int s = 0;

int next_item() { // emulate incoming with the stream

    if (s == N) // all values are streamed
        return -1;

    return s++;
}

std::vector<int> RS(int k) {
    std::vector<int> result;

    std::mt19937 rng(987654321);

    int sp = 0; // position in the stream

    for (;; ) {
        int v = next_item();
        if (v < 0)
            break;
        if (sp < k)
            result.push_back(v);
        else
        {
            std::uniform_int_distribution<int> uni(0, sp);
            int idx = uni(rng);
            if (idx < k)
                result[idx] = v;
        }
        ++sp;
    }
    return result;
}

int main() {
    s = 0;
    N = 10000;
    auto v = RS(10);
    for (auto e : v) {
        std::cout << e << "\n";
    }
    return 0;
}