通过未排序的列表改进搜索

时间:2016-11-03 05:05:09

标签: c++ algorithm sorting search

我的代码花费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来估算要存储的正确断点数?
  • 有更好的解决方案吗?

1 个答案:

答案 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)搜索是否值得?

结论

TBH,我不认为你从这次优化中获得了很多。事实上,我认为你获得了O(logN)的开销。