如何在排序的向量上正确应用擦除-删除习惯用法

how can I correctly apply the erase remove idiom on a sorted vector?

本文关键字:擦除 应用 删除 惯用法 习惯 排序 向量      更新时间:2023-10-16

通常,我们希望应用擦除-删除习惯用法来正确地从向量中删除元素,例如:

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的语法不正确,但希望您能理解)。

谢谢,

本。

您可以使用:

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已排序)。

它不再是擦除-删除习惯用法,但是的,它将正确、最佳、稳定地完成任务。

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

您可以删除无意义的(void)前缀。

假设您想要删除所有等于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);
}