Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ STL矢量元素去除效率_C++_Stl - Fatal编程技术网

C++ STL矢量元素去除效率

C++ STL矢量元素去除效率,c++,stl,C++,Stl,我有一个物体的矢量。所有对象元素都是唯一的。函子是为类的唯一id定义的 从矢量中删除对象元素更有效的方法是什么 myvec.erase(std::remove_if(myvec.begin(), myvec.end(), MyClass(id)), myvec.end()); //OR itonmyvec = std::find_if(myvec.begin(), myvec.end(), MyClass(id)); if(itonmyvec != myvec.end()) myve

我有一个物体的矢量。所有对象元素都是唯一的。函子是为类的唯一id定义的

从矢量中删除对象元素更有效的方法是什么

myvec.erase(std::remove_if(myvec.begin(), myvec.end(), MyClass(id)), myvec.end());

//OR

itonmyvec = std::find_if(myvec.begin(), myvec.end(), MyClass(id));
if(itonmyvec != myvec.end())
    myvec.erase(itonmyvec);
比如说

从范围中删除满足特定条件的所有元素

while被指定为

返回范围中的第一个元素

因为您知道向量中的所有元素都是唯一的,所以可以在第一次匹配后安全地停止搜索。这意味着第二种形式对于这种特定情况可能更快


还请注意,如评论中所述,第一种方法是错误的<如果将迭代器返回到(可能已更新)范围的末尾,则code>remove_。您不想从向量中删除此内容-它保证不匹配您的目标值。

当您使用向量时,两个建议的实现几乎相同

第一个将遍历向量一次,测试每个元素并同时压缩向量,然后最终销毁最后一个元素并缩短向量

第二个将遍历向量直到找到元素,然后遍历向量的其余部分以压缩并最终缩短向量

事实证明,两个版本之间唯一的真正区别是,第二个版本将能够保存O(n/2)个比较的平均值。如果比较便宜,则性能将更多地取决于系统的其他属性,例如,哪个实现对缓存更友好

因此,最终答案只能是基准测试它


注意:第一个版本必须检查
remove\u的结果是否是向量的
end
,以便以相同的方式在两个版本中进行检查(或不进行检查)。

实际最快的方法都不是。这两个元素都会受到标准中附加的约束,即保持其余元素的相对顺序,但这不是您所要求的

因此,最快的解决方案是

  • 找到元素
  • 将其与最后一个元素交换
  • 删除新的最后一个元素

  • 这将执行O(1)赋值,而不是O(N)。

    对于MSalters给出的答案,我已经写下了代码。我无法将代码添加到该答案的注释中,因此将其添加到新答案中。希望有帮助

    //Remove 3rd element
    
    vector<int> v {1,2,3,4,5};          //C++11 compiler needed!
    
    vector<int>::iterator it1 = find(v.begin(), v.end(), 3); 
    
    vector<int>::iterator it2 = --v.end();
    
    std::swap(*it1, *it2);
    
    v.pop_back();
    
    //删除第三个元素
    向量v{1,2,3,4,5}//需要C++11编译器!
    向量::迭代器it1=find(v.begin(),v.end(),3);
    向量::迭代器it2=--v.end();
    标准:交换(*it1,*it2);
    v、 向后弹出();
    
    如果您愿意牺牲异常安全性,您可以比当前接受的答案做得更好:您可以简单地用最后一个元素覆盖要删除的元素,而不是用最后一个元素交换,然后调用
    pop_back()
    。必须从最后一个元素开始向后迭代

    如果您使用整数,这是很好的,而且很可能会节省大量时间。如果您使用的是谁知道在移动复制时会抛出哪些类,那么您就有麻烦了,您的异常安全保证就没有了

    下面是一个示例代码:

    #include <iostream>
    #include <vector>
    
    template <typename Vector, typename Pred>
    void remove(Vector& v, Pred p) {
    
      auto last(v.rbegin());
    
      for (auto pos(last), rend(v.rend()); pos!=rend; ++pos) {
    
        if (p(*pos))
          // overwrite the element to be removed with the currently last element
          *pos = std::move(*last++);
      }
    
      v.erase(last.base(), v.end());  
    }
    
    // pretty print the vector for debugging
    template <typename Vector>
    void show(const Vector& v) {
    
      std::cout << "{ ";
    
      auto pos(v.begin());
    
      auto last(v.end());
    
      if (pos!=last) {
    
        --last;
    
        while (pos!=last)
          std::cout << *pos++ << ", ";
    
        std::cout << *last;
      }
    
      std::cout << " }" << std::endl;
    }
    
    // a simple-minded test that removes all 2s from the vector
    void remove_2s(std::initializer_list<int> l) {
    
      auto equals_two = [](int i) { return i==2;};
    
      std::vector<int> v{l};
    
      remove(v, equals_two);
    
      show(v);
    }
    
    int main() {
    
      remove_2s({1, 2, 3, 2, 5, 7, 4, 2, 6});
    
      remove_2s({ 1, 2 });
    
      remove_2s({ 2, 1 });  
    
      remove_2s({ 2 });
    
      remove_2s({ 2, 2 });  
    
      remove_2s({  });
    
      remove_2s({ 1 });
    }
    
    #包括
    #包括
    模板
    无效删除(矢量和v、Pred p){
    自动最后(v.rbegin());
    用于(自动转位(最后一个)、rend(v.rend());转位!=rend;++pos){
    如果(p(*pos))
    //用当前最后一个元素覆盖要删除的元素
    *pos=std::move(*last++);
    }
    v、 擦除(last.base(),v.end());
    }
    //漂亮的打印矢量以进行调试
    模板
    无效显示(常量向量和v){
    
    std::你为什么不对它进行基准测试?
    擦除
    是一个成员函数,而不是一个
    算法
    @DivyangPatel不,不是真的。获取这一特定知识的努力是最小的,每个回答这个问题的人都很可能会做完全相同的事情(不太可能有人研究过这个特定的事情)。有很多知识和经验可以让人做出有根据的猜测,但是(1)描述完整的推理进入了“过于宽泛”的领域,(2)它仍然只是猜测,而不是一个明确的答案。问题“a比B快”非常窄(也许太窄),问题“我如何决定什么更快?”太宽泛了。@DivyangPatel我明白了。我的即时直觉预测是,没有人手头有基准,到目前为止的答案证实了这一点:有根据的猜测,但仍然是猜测。@DivyangPatel-如果有人回答你说“第一个代码更快”,你会相信他们的话而不自己做基准测试吗?完美而高效的技术!我在下面的一个新答案中添加了相同的代码!如果你愿意牺牲异常安全,你可以做得更好,请参阅我的答案。如果你愿意牺牲异常安全,你可以做得更好,请参阅我的答案。还有
    move\u if_但实际上,我们正在优化O(1)部分,而搜索仍然是O(N)@MSalters是的,我知道,它只影响常数因子。问题是这样的,线性时间搜索是不可避免的,因此我们只能在常数因子上进行改进。@MSalters啊,他只需要删除一个元素。我的错,没有注意到。那么可能是我的“改进”真的没什么大不了的。嗯,我不能在代码审查中就此签字。你为了什么利益而牺牲异常安全?这不值得。你最终会像谷歌一样,为未来的程序员编写指南,他们不能使用异常,因为所有的遗留代码都不是异常安全的。@CodyGray好吧,如果你需要的话“最快”的算法,而且你知道你正在处理的类型不会抛出move-copy,那么我上面写的是安全的。然而,你让我好奇:“你为了什么好处而牺牲了异常安全?”我将在周末对它进行测量。当我们在做的时候:如果