【问题标题】:how can I correctly apply the erase remove idiom on a sorted vector?如何在排序的向量上正确应用擦除删除习语?
【发布时间】:2014-06-09 20:00:29
【问题描述】:

通常,我们希望使用erase remove idiom 来正确地从向量中删除元素,例如:

v.erase( std::remove( std::begin(v), std::end(v), 5 ), std::end(v) ); 

其中 v 是整数向量。

但是如果首先对向量进行排序呢?以下是否会做同样的事情,如果是,它是最优化的方式吗?

std::sort(v.begin(), v.end());

IntegerVector::iterator it = std::lower_bound(v.begin(), v.end(), 5);

if(it != v.end()) {
    (void)v.erase(it, v.end());
}

这是否正确应用了擦除删除习语?在删除过程之后,向量是否仍然排序(我假设是)?我们不需要做这样的事情吗:

(void)v.erase(std::remove(it), v.end());

(std::remove 的语法不正确,但希望你明白)。

谢谢,

本。

【问题讨论】:

  • 注意:你不必写(void)v.erase(...);v.erase(...); 也会这样做。
  • Dieter,这是真的,但擦除返回一个迭代器,对于完全无 lint 的代码,有必要将其强制转换为 void。我喜欢我的代码不掉毛
  • 您似乎正在从第一次出现的 5 开始擦除 所有 元素?

标签: c++ vector stl


【解决方案1】:

你可以使用:

auto range = std::equal_range(std::begin(v), std::end(v), 5);
v.erase(range.first, range.second);

对于 C++03,您必须将 auto 替换为(详细)std::pair<IntegerVector::iterator, IntegerVector::iterator>

std::equal_range 返回一对迭代器,其中范围[first, second) 的值等于给定值(此处为5)(假设v 已排序)。

【讨论】:

  • 谢谢,你能用一些 cmets 解释每行在做什么,那将是最有帮助的。我还应该指出,我目前无法访问 c++11 编译器
  • 为补充评论干杯
【解决方案2】:

这不再是擦除删除的习惯用法,但是,是的,它会正确、优化和稳定地完成工作。

std::remove 在擦除之前将所有不需要的元素收集到一个连续的块中,但是您的排序已经完成,因此不需要它。

你可以去掉无意义的(void)前缀。

【讨论】:

  • 非常感谢 Orbit 的 Lightness Races。 (重新转换为 void,我更喜欢我的代码是无绒毛的,所以任何返回我不需要的东西的语句,我都转换为 void;这只是个人习惯 :-))。
【解决方案3】:

假设您要删除所有等于 5 的元素,可以肯定您的代码不正确。 这是修正后的版本:

std::sort(v.begin(), v.end());

auto lower = std::lower_bound(v.begin(), v.end(), 5);

if(lower != v.end()) {
  auto upper = std::upper_bound(lower,v.end(), 5);
  v.erase(lower,upper);
}

【讨论】:

  • 我给出的例子是直接从 wiki 页面上撕下来的 :-)。实际上,我使用的向量包含一组非重复对象。所以只需删除第一个就足够了(因为只有一个给定值)。
  • @Bgie: std::equal_range 直接做两个边界。
  • @Jarod42 我知道,但我只是复制你的(更好的)解决方案。我只想提供最小的更改来纠正错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多