7

假设您要按值从向量中删除单个元素。remove -erase有什么区别:

vector<int> v;
// add some values
vector<int>::iterator it = remove(v.begin(), v.end(), 5);
v.erase(it);

并查找擦除

vector<int> v;
// add some values
vector<int>::iterator it = find(v.begin(), v.end(), 5);
if(it != v.end())
{
  v.erase(it);
}
4

3 回答 3

14

您的删除-擦除代码不正确。remove-erase 习惯用法如下所示:

vector<int>::iterator it = remove(v.begin(), v.end(), 5);
v.erase(it, v.end());

在这种情况下,它具有擦除所有等于 5 的值的效果,但它最大限度地减少了实现该目标所需的复制量。

您的查找擦除代码仅删除等于 5 的第一个值,因此它可以执行您想要的操作。

您的 remove-erase 代码将所有不等于 5 的值移动到向量的前面(就是这样std::remove做的),擦除向量的剩余元素之一,并在之后留下任何剩余的元素具有未指定的值(这也是remove做)。如果向量不包含 a5开头,则它具有未定义的行为,因为在这种情况下remove会返回v.end()

因此,如果您只想擦除几个等于 5 的单个元素,那么std::remove对您来说没有用,因为它不会保留(其他)5。如果您想将非 5 值移到开头,将 5 值移到末尾,然后再删除 5 中的第一个,那么实际上您可以使用std::partitionnot with 来执行此操作std::remove

auto it = partition(v.begin(), v.end(), [](int i) { return i != 5; });
if (it != v.end()) v.erase(it);

虽然,由于一个 5 与另一个一样好,因此您可以通过擦除最后一个 5 而不是第一个来获得相同的结果,并且当有多个 5 时效率更高:

auto it = partition(v.begin(), v.end(), [](int i) { return i != 5; });
if (it != v.end()) v.pop_back();

如果你能以某种方式确定向量最初包含一个等于 5 的元素(不多或少),那么你的两位代码会做同样的事情在那种情况下,您不需要it != v.end()在查找擦除代码中进行测试,您会知道它不相等。你可以这样做v.erase(find(v.begin(), v.end(), 5))

于 2013-11-15T11:33:11.210 回答
1

不同之处在于,如果有多个值与给定的值匹配,则remove解决方案会将所有不匹配的项目移至开头(感谢 Steve Jessop 在评论中指出)。只有erase这样才会删除这些的第一次出现;最终得到一个 re-sorted vector,其中包含给定值的少一个。

-find解决方案只会删除第一次出现,而不改变向量的顺序。

于 2013-11-15T11:29:26.270 回答
-1

您是否真的试图看到差异?

在第一段代码中,std::remove通过将所有等于 5 的元素放在向量的末尾来转换向量,并将迭代器返回到的末尾。当你打电话时erase,你删除新结束后的第一个元素。你可能想做:

vector<int>::iterator it = remove(v.begin(), v.end(), 5);
v.erase(it, v.end());

这将删除所有值为 5 的元素。

在第二个示例中,std::find查找向量的第一个等于 5 的元素并返回一个迭代器。调用erase只会删除该元素。

这就是区别。

于 2013-11-15T11:31:37.077 回答