当我不关心顺序并且没有重复项时,更快的擦除删除成语?

faster erase-remove idiom when I don't care about order and don't have duplicates?

本文关键字:擦除 成语 删除 顺序 不关心      更新时间:2023-10-16

我有一个对象向量,想按值删除。 但是,该值仅出现一次,我不关心排序。

显然,如果这种按值删除非常普遍,和/或数据集非常大,那么向量就不是最好的数据结构。 但是,假设我已经确定情况并非如此。

需要明确的是,如果我的代码是 C,我会对以下内容感到满意:

void delete_by_value( int* const piArray, int& n, int iValue ) {
for ( int i = 0; i < n; i++ ) {
if ( piArray[ i ] == iValue ) {
piArray[ i ] = piArray[ --n ];
return;
}
}
}

似乎使用 std::algos 和容器方法的"现代习语"方法是:

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

但这应该慢得多,因为对于随机存在的元素,它是 n/2 移动和 n 比较。 我的版本是 1 个移动和 n/2 比较。

当然,在"现代成语"中,有比擦除-删除-成语更好的方法吗? 如果不是,为什么不呢?

使用std::find替换循环。从end迭代器的前置函数中获取替换值,并使用该迭代器erase该元素。由于此迭代器是最后一个元素,因此erase很便宜。奖励:bool成功检查和templateint的回报。

template<typename T>
bool delete_by_value(std::vector<T> &v, T const &del) {
auto final = v.end();
auto found = std::find(v.begin(), final, del);
if(found == final) return false;
*found = *--final;
v.erase(final);
return true;
}
当然,在

"现代成语"中,有比擦除-删除-成语更好的方法吗?

标准库中的每个利基用例都没有现成的功能。不稳定删除是未提供的功能之一。不过,不久前有人提出了(p0041r0(。同样,对于不包含重复项的向量的特殊情况,也没有特殊版本的算法。

因此,如果您希望使用最佳算法,则需要自己实现算法。线性搜索std::find。之后,您只需要从最后一个元素分配并最终将其弹出即可。

如果使向量的大小变小,大多数std::vector::resize实现都不会重新分配。因此,以下内容可能具有与 C 示例类似的性能。

void find_and_delete(std::vector<int>& v, int value) {
auto it = std::find(v.begin(), v.end(), value);
if (it != v.end()) {
*it = v.back();
v.resize(v.size() - 1);
}
}

C++方式与std::vector基本相同:

template <typename T>
void delete_by_value(std::vector<T>& v, const T& value) {
auto it = std::find(v.begin(), v.end(), value);
if (it != v.end()) {
*it = std::move(v.back());
v.pop_back();
}
}