所以在c ++中,我在随机数生成器中使用mt19937 engine 和 uniform_int_distribution ,如下所示:
// Heavy work dispatched to a separate thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
temp = [ayatArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"(self.SratNo == %@)",mood]];
NSSet *uniqueSet = [NSSet setWithArray:[temp valueForKey:@"Para"]];
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:nil ascending:YES];
uniqueParasArray = [uniqueSet sortedArrayUsingDescriptors:[NSArray arrayWithObject:sort]];
currentParaNum = [uniqueParasArray[i] integerValue];
NSNumber *mood = @(currentParaNum);
NSArray *paraWiseAyats = [[NSArray alloc] init];
paraWiseAyats = [temp filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"(self.Para == %@)",mood]];
ayatArrayForTableView = [paraWiseAyats mutableCopy];
[self.translationTableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
});
我需要的是改变上面的生成器,以便有一个包含许多整数的缓存,当我反复使用上面的生成器时,我需要将其排除在外。 如何更改以上内容以实现此目的?
答案 0 :(得分:3)
有很多方法可以做到这一点。一种简单的方法是将您的“排除的数字”保留在std::set
中,并在每次生成随机数后,检查它是否在集合中,然后再生成一个新的随机数-重复此操作,直到获得一个不在集合中的数字,然后将其返回。
顺便说一句;虽然发行版的构建成本低廉,但引擎却并非如此。您不想每次调用该函数时都重新构建mt19937
,而是一次创建它,然后重新使用它。您可能还想使用比当前时间(秒)更好的种子。
答案 1 :(得分:1)
您是否1)尝试在离散间隔内不进行替换而进行采样?还是2)区间内的补丁分布相当稳定?
如果是1),则可以按照此处的答案使用std :: shuffle How to sample without replacement using c++ uniform_int_distribution
如果是2),则可以使用std :: discrete_distribution(元素0对应于lwr_lm
),并将不需要的数字加权为零。显然,upper_lm-lwr_lm
中的内存需求是线性的,因此如果内存需求很大
答案 2 :(得分:1)
我将为这个问题提出两个类似的解决方案。它们基于概率结构,并为您提供“可能在缓存中”或“绝对不在缓存中”的答案。有误报但没有误报。
Perfect hash function。有许多实现,包括one from GNU。基本上,在一组缓存值上运行它,并使用生成的完美哈希函数拒绝采样值。您甚至不需要维护哈希表,只需将随机值映射到整数索引即可。一旦索引在哈希范围内,请拒绝该数字。完美意味着您只需要打一个电话即可检查,结果将告诉您该号码已在集合中。有潜在的冲突,因此可能会出现误报。
Bloom filter。同样的想法,使用您愿意保留的每个缓存项的任意位来构建过滤器,并通过快速检查获得“可能在缓存中”的答案或清除否定的答案。您可以将答案精度换成内存,反之亦然。误报是可能的
答案 3 :(得分:0)
这可能不是最漂亮的解决方案,但是什么使您无法维护该缓存并在返回之前检查其存在?不过,对于大型缓存,它会变慢。
#include <random>
#include <time.h>
#include <set>
std::set<int> cache;
int get_random(int lwr_lm, int upper_lm){
std::mt19937 mt(time(nullptr));
std::uniform_int_distribution<int> dist(lwr_lm, upper_lm);
auto r = dist(mt);
while(cache.find(r) != cache.end())
r = dist(mt);
return r;
}
答案 4 :(得分:0)
正如@virgesmith所说,在回答问题时,这可能是更好的解决方案。
对于大范围wiki,带有缓存并用于过滤未来生成的方法效率不高。
在这里,我用不同的方法编写了一个简单的示例,但是您会受到记忆的限制。您选择一个随机数作为缓冲区,然后将其删除以进行下一次迭代。
#include <random>
#include <time.h>
#include <iostream>
int get_random(int lwr_lm, int upper_lm, std::vector<int> &buff, std::mt19937 &mt){
if (buff.size() > 0) {
std::uniform_int_distribution<int> dist(0, buff.size()-1);
int tmp_index = dist(mt);
int tmp_value = buff[tmp_index];
buff.erase(buff.begin() + tmp_index);
return tmp_value;
} else {
return 0;
}
}
int main() {
// lower and upper limit for random distribution
int lower = 0;
int upper = 10;
// Random generator
std::mt19937 mt(time(nullptr));
// Buffer to filter and avoid duplication, Buffer contain all integer between lower and uper limit
std::vector<int> my_buffer(upper-lower);
std::iota(my_buffer.begin(), my_buffer.end(), lower);
for (int i = 0; i < 20; ++i) {
std::cout << get_random(lower, upper, my_buffer, mt) << std::endl;
}
return 0;
}
编辑:更清洁的解决方案here