- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我想有效地生成一个(封闭)范围内的唯一(非重复)整数的随机样本 [0, rnd_max]
,范围内的每个数字都可以选择,并且每个都与样本权重相关联(权重越大,选择该数字的可能性就越大,下一个被选择的概率恰好是 weight[i]/sum(weight[not_taken])
如果它还没有被纳入样本)。
我看到 C++ 有 std::discrete_distribution
可以生成随机加权整数,但是如果我用它来生成随机整数并丢弃重复的整数,当要获取的样本相对于长度来说很大时在可能的范围内,将会有很多已经采集的失败样本,导致程序效率极低。我不清楚 Floyd 算法是否对样本权重 (https://math.stackexchange.com/questions/178690/whats-the-proof-of-correctness-for-robert-floyds-algorithm-for-selecting-a-sin) 的情况有一些扩展 - 我个人想不出一个。
也可以例如使用 std::discrete_distribution
将权重降为零,或执行部分加权洗牌,如以下答案:C++. Weighted std::shuffle - 但在该答案中,std::discrete_distribution
在每次迭代时重新生成,因此运行时间变为二次方(它需要循环遍历每次传递给它的权重)。
想知道 C++ 中唯一整数的有效加权随机样本是什么,它适用于不同的样本大小(例如,可用范围内的样本数的 1% 到 90%)。
#include <vector>
#include <random>
#include <algorithm>
int main()
{
size_t rnd_max = 1e5;
size_t ntake = 1e3;
unsigned int seed = 12345;
std::mt19937 rng(seed);
std::gamma_distribution<double> rgamma(1.0, 1.0);
std::vector<double> weights(rnd_max);
for (double &w : weights) w = rgamma(rng);
std::vector<int> chosen_sample(ntake);
// sampler goes here...
return 0;
}
最佳答案
使用扩充二叉搜索树可以很好地解决这个问题。它给出了一个时间复杂度为 O(k log n) 的随机采样 k 个元素的算法。
思路是这样的。假设您将所有元素按排序顺序存储在一个数组中,每个元素都标有其权重。然后,您可以按如下方式(低效地)解决此问题:
如果你按上面提到的方式实现它,每次选择一个随机元素的过程都将花费 O(n) 的时间:你必须遍历数组的所有元素,然后在你选择它之后从某处删除一个元素.那不是很好;整体运行时间为 O(kn)。
我们可以通过以下方式稍微改进这个想法。当存储数组中的所有元素时,让每个元素都存储其实际权重和所有在它之前的元素的组合权重。现在,要找到您要采样的元素,您不需要使用线性搜索。您可以改为对数组使用 二分搜索 以在时间 O(log n) 中定位您的元素。但是,这种方法的总体运行时间仍然是每次迭代的 O(n),因为这是删除您选择的元素的成本,所以我们仍然处于 O(kn) 范围内。
但是,如果您不将元素存储在排序的数组中,其中每个元素存储它之前的所有元素的权重,而是在平衡二分查找中树,其中每个元素存储其左子树中所有元素的权重,您可以模拟上述算法(二分搜索被替换为遍历树)。此外,这样做的好处是可以在 O(log n) 时间内从树中删除一个元素,因为它是一个平衡的 BST。
(如果您好奇如何通过遍历找到您想要的元素,请快速搜索“order statistics tree”。这里的想法本质上是这个想法的概括。)
按照@dyukha 的建议,您可以通过在时间为 O(n) 的项目中构建一个完美平衡的树来获得每个操作的 O(log n) 时间(实际上不必为此对项目进行排序工作的技术 - 你知道为什么吗?),然后每次你需要删除一些东西时使用标准的树删除算法。这给出了 O(k log n) 的整体解决方案运行时间。
关于C++ 具有权重的随机非重复整数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57599509/
我正在尝试学习 Fortran,并且看到了很多不同的定义,我想知道他们是否正在尝试完成同样的事情。以下有什么区别? 整数*4 整数(4) 整数(kind=4) 最佳答案 在 Fortran >=90
我以前从未编程过,最近(1 周前)才开始学习!第一门类(class)是函数式编程,使用 Haskell。 我有一项学校作业,我想通过删除一两个步骤来改进它,但我遇到了一个讨厌的错误。 基本上,我创建了
给定以下GraphQL请求和变量: 请求: query accounts($filter:AccountFilter, $first_:String, $skip_:Int) { accounts
我已经搜索了 StackOverflow,但找不到关于如何检查计算器应用程序的数字输入正则表达式的答案,该计算器应用程序将检查每个 keyup 的以下格式(jquery key up): 任何整数,例
类似于我上一篇致歉的文章,但没有那么长篇大论。基本上我想知道当每次重绘调用只重绘屏幕的一小部分时,优化重绘到 JFrame/JPanel 的最佳选择是什么。 此外,除了重绘重载之外,我并不是 100%
所以在我的教科书中有一个使用 f# 的递归函数的例子 let rec gcd = function | (0,n) -> n | (m,n) -> gcd(n % m,m);; 使用此功能,我的教科书
我有一个数据结构,例如表达式树或图形。我想添加一些“测量”功能,例如depth和 size . 如何最好地键入这些函数? 我认为以下三个变体的用处大致相同: depth :: Expr -> Int
这样写比较好 int primitive1 = 3, primitive2 = 4; Integer a = new Integer(primitive1); Integer b = new Inte
我是 Java 8 新手,想根据键对 Map 进行排序,然后在值内对每个列表进行排序。 我试图寻找一种 Java 8 方法来对键和值进行排序。HashMap>映射 map.entrySet().str
这就是我的目标... vector ,int> > var_name (x, pair (y),int>); 其中 x 是 vector var_name 的大小,y 是对内 vector 的大小。
这里是 an answer to "How do I instantiate a Queue object in java?" , Queue is an interface. You can't i
这个问题在这里已经有了答案: Weird Integer boxing in Java (12 个答案) Why are autoboxed Integers and .getClass() val
我们可以使用 C++ STL 做这样的事情吗?如果是,我将如何初始化元素?我试图这样做,但没有成功。 pair,vector>p; p.first[0]=2; 最佳答案 Can we do som
您好,我正在尝试为百分比和整数数组中的数字找到索引。假设 arraynum = ['10%','250','20%','500'] 并且用户发送一个值 15%,这个数字在哪个范围内居住?我可以使用这段
我与三列有关系:ProductName、CategoryID 和 Price。我需要选择仅那些价格高于给定类别中平均产品价格的产品。(例如,当apple(ProductName)是fruit(Cate
我已经坚持了一段时间,我正在尝试将一些数据配对在一起。这是我的代码。 #include #include using namespace std; int main() { pair data(
我收到错误:'(Int, Int)' 与 'CGPoint' 不相同 如何将 (Int, Int) 转换为 CGPoint let zigzag = [(100,100), (100,150)
我在 .cpp 文件中发现了以下代码。我不理解涉及头文件的构造或语法。我确实认识到这些特定的头文件与 Android NDK 相关。但是,我认为这个问题是关于 C++ 语法的一般问题。这些在某种程度上
我将这些输入到 Scala 解释器中: val a : Integer = 1; val b : Integer = a + 1; 我收到消息: :5: error: type mismatch;
C++:vector>v(size);当我试图打印出值时显示 0 作为值,但是当未声明 vector 大小时它显示正确的输出?为什么这样?例如: int x; cin>>x; vector>v(x);
我是一名优秀的程序员,十分优秀!