有没有一种有效的方法来使用随机数去重?
Is there an efficient way to use random number deduplication?
我正在制作一个使用随机数的程序。
我写了如下代码,但是循环次数比我预期的要多
有没有一种有效的方法来使用随机数去重?
#include <iostream>
#include <cstdlib>
#include <ctime>
#define MAX 1000
int main(void)
{
int c[MAX] = {};
int i, j = 0;
srand((unsigned int)time(NULL));
for (i = 0; i < MAX; i++)
{
c[i] = rand() % 10000;
for (j = 0; j < i; j++)
{
if (c[i] == c[j])
{
i--;
break;
}
}
}
for (i = 0; i < MAX; i++)
{
std::cout << c[i] << std::endl;
}
return 0;
}
你可以利用std::shuffle
。
用递增的数字填充 vector
直到 MAX
然后洗牌。
#include <random>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <vector>
#define MAX 1000
int main()
{
std::vector<int> v(MAX) ; // vector with 1000 ints.
std::iota (std::begin(v), std::end(v), 0);
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
}
这里有一个版本,像TruthSeeker的答案一样,避免初始化一个最大大小的数组,所以它占用的内存更少。它具有均匀采样。
#include <random>
#include <cassert>
#include <iostream>
#include <unordered_map>
#include <vector>
std::vector<int> random_set(int count, int maximum_value)
{
assert(count <= maximum_value + 1);
std::vector<int> output;
std::unordered_map<int, int> jump;
auto helper_maximum = maximum_value;
std::random_device rd;
std::mt19937 gen(rd());
for (int i = 0; i < count; ++i, --helper_maximum)
{
const auto selector_origin = std::uniform_int_distribution<int>(0, helper_maximum)(gen);
auto selector = selector_origin;
while (true)
{
auto it = jump.find(selector);
if (it == jump.end()) break;
selector = it->second;
}
jump[selector_origin] = helper_maximum;
output.push_back(selector);
}
return output;
}
int main()
{
random_set(10, 15000);
}
您所描述的是 sampling without replacement. std::sample
正是这样做的,您只需要为其提供您的人数。
std::ranges::views::iota
可以是你的人口而不需要存储10000个数字。
#include <algorithm>
#include <random>
#include <ranges>
#include <iostream>
int main()
{
std::vector<int> c(1000);
std::mt19937 gen(std::random_device{}()); // or a better initialisation
auto numbers = std::ranges::views::iota(0, 9999);
std::sample(numbers.begin(), numbers.end(), c.begin(), 1000, gen);
for (int i : c)
{
std::cout << i << std::endl;
}
}
我正在制作一个使用随机数的程序。 我写了如下代码,但是循环次数比我预期的要多 有没有一种有效的方法来使用随机数去重?
#include <iostream>
#include <cstdlib>
#include <ctime>
#define MAX 1000
int main(void)
{
int c[MAX] = {};
int i, j = 0;
srand((unsigned int)time(NULL));
for (i = 0; i < MAX; i++)
{
c[i] = rand() % 10000;
for (j = 0; j < i; j++)
{
if (c[i] == c[j])
{
i--;
break;
}
}
}
for (i = 0; i < MAX; i++)
{
std::cout << c[i] << std::endl;
}
return 0;
}
你可以利用std::shuffle
。
用递增的数字填充 vector
直到 MAX
然后洗牌。
#include <random>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <vector>
#define MAX 1000
int main()
{
std::vector<int> v(MAX) ; // vector with 1000 ints.
std::iota (std::begin(v), std::end(v), 0);
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
}
这里有一个版本,像TruthSeeker的答案一样,避免初始化一个最大大小的数组,所以它占用的内存更少。它具有均匀采样。
#include <random>
#include <cassert>
#include <iostream>
#include <unordered_map>
#include <vector>
std::vector<int> random_set(int count, int maximum_value)
{
assert(count <= maximum_value + 1);
std::vector<int> output;
std::unordered_map<int, int> jump;
auto helper_maximum = maximum_value;
std::random_device rd;
std::mt19937 gen(rd());
for (int i = 0; i < count; ++i, --helper_maximum)
{
const auto selector_origin = std::uniform_int_distribution<int>(0, helper_maximum)(gen);
auto selector = selector_origin;
while (true)
{
auto it = jump.find(selector);
if (it == jump.end()) break;
selector = it->second;
}
jump[selector_origin] = helper_maximum;
output.push_back(selector);
}
return output;
}
int main()
{
random_set(10, 15000);
}
您所描述的是 sampling without replacement. std::sample
正是这样做的,您只需要为其提供您的人数。
std::ranges::views::iota
可以是你的人口而不需要存储10000个数字。
#include <algorithm>
#include <random>
#include <ranges>
#include <iostream>
int main()
{
std::vector<int> c(1000);
std::mt19937 gen(std::random_device{}()); // or a better initialisation
auto numbers = std::ranges::views::iota(0, 9999);
std::sample(numbers.begin(), numbers.end(), c.begin(), 1000, gen);
for (int i : c)
{
std::cout << i << std::endl;
}
}