C++ 从非常大的值集中快速加权随机选择

C++ 从非常大的值集中快速加权随机选择,c++,random,selection,complexity-theory,probability,C++,Random,Selection,Complexity Theory,Probability,我目前正在处理一个问题,需要从集合中随机选择一个元素。每个元素都有与其相关的权重选择概率 我的问题是,对于元素数量较少的集合(例如5-10个),解决方案的复杂度运行时间是可以接受的,但是随着元素数量的增加(例如1K或10K等),运行时间变得不可接受 我目前的策略是: 选择范围为[0,1]的随机值X 迭代元素对其权重求和,直到和大于X 选择并返回导致总和超过X的元素 对于大型集合和大量选择,此过程开始表现出二次行为,简言之,有没有更快的方法?也许有更好的算法?假设元素权重是固定的,您可以使用预计算

我目前正在处理一个问题,需要从集合中随机选择一个元素。每个元素都有与其相关的权重选择概率

我的问题是,对于元素数量较少的集合(例如5-10个),解决方案的复杂度运行时间是可以接受的,但是随着元素数量的增加(例如1K或10K等),运行时间变得不可接受

我目前的策略是:

选择范围为[0,1]的随机值X 迭代元素对其权重求和,直到和大于X 选择并返回导致总和超过X的元素
对于大型集合和大量选择,此过程开始表现出二次行为,简言之,有没有更快的方法?也许有更好的算法?

假设元素权重是固定的,您可以使用预计算的和。这与直接使用累积概率函数,而不是密度函数类似激动

然后,可以将查找实现为二进制搜索,因此在元素数量上为logN

二进制搜索显然需要随机访问权重容器

或者,使用std::map和上限方法


你想使用沃克算法。有N个元素,有一个设置 上的成本。但是,采样成本为O1。请参阅

A.J.Walker,一种生成 离散随机变量和一般分布,ACM TOMS 3253-256 1977 克努特,TAOCP,第2卷,第3.4.1.A节。 随机选择类
实现此算法。

如果您有足够快的方法对随机元素进行统一采样,您可以使用拒绝采样;您只需要知道最大权重。它的工作原理如下:假设最大权重为M。在[0,1]中均匀地选择一个数字X.重复采样元素,直到找到一个重量至少为M*X的元素;选择此元素


或近似的解决方案:随机选取100个元素;在这个集合中选择一个与权重成比例的。< /P>你应该删除C++标签,因为这是一个适用于任何语言的通用算法问题。这是真的,但是我更喜欢C++中的解决方案,因为我的编码问题是C++,你是指使用STL上边界的下界绑定?d您提供了一个简单的示例?@Curzon:要将Keith的建议应用于您的代码,而不是为所有元素指定权重,请将权重+前面权重的总和指定。然后,选择一个随机值X[0,1,并使用set::lower_-bound获取元素的迭代器,该元素的值不小于X。或者,如果元素应该严格大于XA位,则使用upper_-bound来帮助运算,但对于未来的读者来说,这是正确的答案。O1算法比Olog n算法更好,从C++11开始:您能例如:查看Knuth的教科书,了解算法的描述。RandomLib的链接提供了一个实现。

#include <iostream>
#include <map>
#include <stdlib.h>

int main ()
{
  std::map<double, char> cumulative;
  typedef std::map<double, char>::iterator It;

  cumulative[.20]='a';
  cumulative[.30]='b';
  cumulative[.40]='c';
  cumulative[.80]='d';
  cumulative[1.00]='e';

  const int numTests = 10;
  for(int i = 0;
      i != numTests;
      ++i)
  {
      double linear = rand()*1.0/RAND_MAX;  
      std::cout << linear << "\t" << cumulative.upper_bound(linear)->second << std::endl;
  }

  return 0;
}