我的代码花费40%的时间搜索未分类的向量。更具体地说,搜索功能my_search
重复接收长度为N
的单个未排序向量,其中N
可以采用10到100,000之间的任何值。与每个元素相关的权重具有相对较小的方差(例如[0.8,0.81,0.85,0.78,0.8,0.7,0.84,0.82,...])。
算法my_search
首先对每个对象的所有权重求和,然后用替换样本计算N
个元素的平均值(与向量的长度一样多)。该算法非常类似于
int sum_of_weight = 0;
for(int i=0; i<num_choices; i++) {
sum_of_weight += choice_weight[i];
}
int rnd = random(sum_of_weight);
for(int i=0; i<num_choices; i++) {
if(rnd < choice_weight[i])
return i;
rnd -= choice_weight[i];
}
来自this post。
我可以在搜索之前对矢量进行排序,但是需要O(N log N)的时间(取决于所使用的排序算法)并且我怀疑(但可能是错误的,因为我没有尝试过)我会获得很多时间,特别是因为权重几乎没有变化。
另一个解决方案是存储一系列积分前的重量信息。例如,在对矢量求和时,每N / 10个元素,我可以存储已经总和了多少权重的信息。然后,我可以先将rnd
与这10个断点进行比较,并仅搜索向量总长度的十分之一。
N
来估算要存储的正确断点数?答案 0 :(得分:5)
log(N)
解决方案{
std::vector<double> sums;
double sum_of_weight = 0;
for(int i=0; i<num_choices; i++) {
sum_of_weight += choice_weight[i];
sums.push_back(sum_of_weight);
}
std::vector<double>::iterator high = std::upper_bound(sums.begin(), sums.end(), random(sum_of_weight));
return std::distance(sums.begin(), high);
}
基本上你有一个更好的方法来解决它的想法,而不是只存储10个元素,存储所有元素并使用二进制搜索来找到最接近你的值的索引。
即使此解决方案为O(logN)
,您也必须问自己是否值得。是否值得创建一个额外的向量,从而累积额外的时钟周期来存储向量中的内容,向量调整大小所需的时间,调用函数执行二进制搜索所需的时间等等?
正如我上面写的那样,我意识到你可以使用deque
代替,这几乎可以摆脱因必须调整和复制矢量内容而不影响O(1)而造成的性能损失查找向量。
所以我猜问题仍然存在,将元素复制到另一个容器然后只进行O(logN)
搜索是否值得?
O(logN)
的开销。