对于我的程序,到目前为止,我需要在[0..k [不时]中使用一个随机值,并使用C ++ 11 <random>
功能非常好。我目前的代码类似于
class Random
{
public:
Random() : rng( rd() ) { }
inline int getRandNum( int limit ) { return ( numbers(rng) % limit ); }
private:
std::random_device rd;
std::mt19937 rng;
std::uniform_int_distribution<int> numbers;
};
现在,我需要在[0..k [中]连续绘制 n 不同的值。我在<random>
中寻找允许的东西,但是我无法找到它,或者这样的东西还不存在。有没有比调用我的getRandNum函数更聪明,更优雅的方法,并重复直到我得到n个不同的值?
编辑:提出一个想法,在我的程序中k是几千和几十。
答案 0 :(得分:2)
此解决方案不是C ++特定的,但可以使用任何语言轻松实现。
你想要的基本上是数字0到k,并选择前n个数字,其中n <= k。 这可以使用油藏采样算法来完成。有关伪代码,请参阅此维基百科link。
请注意,可以在不存储所有k个数字的情况下获取n个数字并对其进行混洗。也就是说,可以只使用O(n)空间,其中n是您希望获得的随机数的数量,而不是O(k)。如果我们假设生成随机数需要O(1)时间,则该算法的时间复杂度为O(k)。
答案 1 :(得分:1)
如果k是几千且n是十,那么排列生成真的不是最好的选择。但是调用getRandNum也不是你想要的,因为它可以多次返回相同的值。
一种选择是一次生成随机序列,检查数字是否重复。最简单(也可能是最有效)的方法是使用set
。
像这样:
#include <vector>
#include <set>
#include <iostream>
#include <random>
class Random
{
public:
Random() : rng( rd() ) { }
inline int getRandNum( int limit ) { return ( numbers(rng) % limit ); }
std::set<int> getRandSequence(int limit, int n);
private:
std::random_device rd;
std::mt19937 rng;
std::uniform_int_distribution<int> numbers;
};
std::set<int> Random::getRandSequence(int limit, int n)
{
std::set<int> generatedSequence;
while (generatedSequence.size() < n) //size() for set is O(1) if I'm not mistaken
generatedSequence.insert(getRandNum(limit));
return generatedSequence;
}
int main()
{
Random r;
auto sequence = r.getRandSequence(1000, 10);
std::cout << "Seq;uence: " << std::endl;
for (int number : sequence)
std::cout << number << std::endl;
std::cout << "End" << std::endl;
return 0;
}
顺便说一下,random_device
创建是昂贵的,但据我记忆,uniform_int_distribution
创建并非如此。所以这可能更有效:
std::set<int> Random::getRandSequence(int limit, int n)
{
std::uniform_int_distribution<int> uiniformDistribution(0, limit);
std::set<int> generatedSequence;
while (generatedSequence.size() < n)
generatedSequence.insert(uiniformDistribution(rng));
return generatedSequence;
}
此外,当您获得统一分发然后将% limit
应用于它时,您将无法再获得统一分发。
答案 2 :(得分:0)
std::random_device rd; // obtain a random number from hardware
std::mt19937 eng(rd()); // seed the generator
std::uniform_int_distribution<> distr(0, 1500); // define the range
for(int a=0; a<limit; a++){
cout << distr(eng); //draw random nubmer