我想在0、1、2,...,n-1中采样k个不同的(不替换)随机数。
在我看来,我在网上可以找到的大多数解决方案都需要一个存储所有数字的数组,然后以某种方式将其洗牌。但是,它占用O(n)空间。我想知道C ++中是否有任何方法可以不生成数组。
答案 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;
}