std::vector::reserve(未知m),我知道m<<;N(通常)并且知道N

std::vector::reserve( unknown m ), I know that m<<N (usually) and know N

本文关键字:lt 通常 我知道 reserve vector 未知 std      更新时间:2023-10-16

我有一些代码可以处理N对象,然后根据一些自定义条件,只返回某些m索引的结果。

这里有一个坚实的例子(查询字符串str上的所有' '字符):-

std::vector<int> reports; //will keep index of ' ' in "str"
for(int i=0;i<N;i++){  // str.size() = "N"
bool condition = str.at(i)==' ';  //"str" is string   #B
if(condition){ //rarely true
reports.push_back(i); 
}
}
//now reports.size() = m

在这些块中,我知道m总是小于或等于N,并且通常m << N

在现实生活中,区块更复杂,但共享类似的算法:-

//int "N" is a local variable, it is not a constant. 
std::vector<Input> inputs; 
std::vector<Report> reports;  //"Report" is any type of result, actually
int outOfLoopVariable=0; 
for(int i=0;i<N;i++){
bool condition = some logic #B about "inputs[i]" and "outOfLoopVariable";
outOfLoopVariable= ....; //some complex logic #B
int var1 = ....; //some complex logic #B
//var2, var3, etc.
if(condition){ //rarely true
reports.push_back(Report(i,var1,var2,...)); 
}
}

原始问题

算法#B的总复杂度=O(N)
std::vector::push_back的总复杂程度=

  • O(m*log(m))在大多数情况下(当m<<N时)
  • 最坏情况下的O(N*log(N))(当m~N时)

正如oLen所指出的,这是完全错误的。然而,我决定把它留作参考

问题

(编辑)算法#B需要多次重新分配vector

问题

如何使上述块的复杂性为O(N)
(编辑,感谢oLen)如何避免不必要的vector内部预订(1->2->4->…)?

我糟糕的解决方案

多年来,我一直通过以下方法来解决这个问题:-

  1. reports.reserve(N)在第一个语句中-在大多数情况下,这是一个过度保留
    report是一个大对象,而N非常大(profiled,10000+)时,这真的很糟糕
  2. 循环两次。
    • 第一个循环确定m
    • 然后是CCD_ 22
    • 最后,第二个循环执行实际的reports.push_back(i);
    • 这不方便。代码重复往往会导致轻微的可维护性问题
      (可以通过lambda[&]部分解决,稍微牺牲可读性)
    • 此外,粗略地说,#B的复杂性现在是O(2*n)
    • 。。。或者CCD_ 27,如果我可以省略第一个循环的一些计算

我希望有更好的方法。

答案:只是不要更改代码,也不要使用reserve

std::vector::push_back的复杂度是恒定的(考虑到摊销时间),所以只要使用它就可以了

有第三种方法:使用链表report。没有超额预订。没有额外的循环。

但速度可能较慢。