擦除删除成语的性能增益从何而来
Where is the performance gain of the erase-remove idiom coming from
我需要从向量中删除满足特定条件的所有元素。
我的第一个方法是遍历向量并在所有满足条件的元素上调用 vector::eras。
据我了解,vector::erase
对于这个用例来说性能很差,因为它从底层数组中删除了项目,并将矢量的其余部分向前移动了一个元素(如果您擦除一系列元素,则移动更多(。 移除多个元素时,每次移除时都会移动后部元素。
remove
算法获取所有要删除的元素,并将它们移动到矢量的末尾,因此您只需删除矢量的后部,这不涉及移动。
但为什么这比擦除更快?(它更快吗?(
将元素移动到末尾是否意味着像vector::erase
一样向前移动所有以下元素?
为什么,删除只有O(n(的复杂性?
这里的性能问题不是关于擦除要删除的元素,或者将它们移动到末尾(实际上并没有发生(,而是关于移动要保留的元素。
如果您在要删除的每个元素上使用erase
,则需要在这些元素之后移动所有元素...对于每次调用erase
.通常,如果要删除k
元素,则将元素移动到最新元素(在矢量中(之后k
次,而不是仅移动一次。
但是如果你调用remove
,你只会移动一次(见下面的示例(。
一个小示例可以更好地理解这两种方法的工作原理:
假设您有一个大小为 1000 的向量,并且要删除的元素位于位置 17 和 37。
erase
作用于要删除的两个元素:
- 当你为第 17 个元素调用
erase()
时,您需要将元素 18 移动到 999、982 个元素。
当你为第 36 个元素 - 调用
erase()
时(现在是第 36 个元素!(,您需要将元素 37 移动到 998、962 个元素。
您总共移动了 962 + 982 = 1944 个元素,其中 962 个元素被白白移动了两次。
使用remove
,发生的情况如下:
element 0 does not change;
element 1 does not change;
...
element 17 is "discarded";
element 18 is moved at position 17;
element 19 is moved at position 18;
...
element 36 is moved at position 35;
element 37 is "discarded";
element 38 is moved at position 36;
...
element 999 is moved at position 997.
您总共移动了 998 个元素(1000 减去您删除的两个元素(,这比以前方法的 1943 个元素要好得多。如果要删除的元素超过 2 个,那就更好了。
您可以查看 en.cppreference.com 上可能的实现,以更好地了解std::remove
的工作原理。
优点在于std::remove
一次只删除一个元素。例如,如果对std::remove
的调用导致删除向量的前 10 个元素,它会将第 11 个元素直接移动到第 1 个位置,将第 12 个元素直接移动到第 2 个位置,依此类推...... 然而,如果您一次擦除一个前 10 个元素,它会将您擦除的元素之后的每个元素移回 1。然后你会删除下一个,每个元素都必须再次移动。这将对每个被擦除的元素重复。
此外,删除的元素不必是顺序的,此优势就会发生。例如,如果对 remove 的调用导致从第一个元素开始的所有其他元素被删除。首先,第二个元素将移动到第一个位置,这将留下两个元素的间隙,直到下一个可保留的元素。然后第 4 个元素将直接移动到第 2 个位置,留下 3 个元素的间隙,依此类推。
另外,稍作修正:
remove 算法获取所有要删除的元素,并将它们移动到向量的末尾
删除算法不会这样做。它不关心要删除的元素会发生什么。它们只是被将要保留的元素所取代。未指定调用删除后末尾的元素值。您描述的算法是分区(具有反向比较函数(。
- 将数组的地址分配给变量并删除
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- C/C++编译器通常会删除重复的库吗
- 从链接列表c++中删除一个项目
- C++如何通过用户输入删除列表元素
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 是否需要删除包含对象的"pair"?
- 如何在自删除后将对象设置为nullptr
- 迭代时从向量和内存中删除对象
- 使用函数"remove"删除重复元素
- 如何从多映射中删除特定的重复项
- 运算符C++ "delete []"仅删除 2 个前值
- 删除指向指针的指针是运行时错误吗
- C++14 中unordered_map矢量和擦除删除成语的奇怪行为
- 当我不关心顺序并且没有重复项时,更快的擦除删除成语?
- 擦除删除成语的性能增益从何而来
- 为什么擦除-删除成语不适用于反向迭代器
- 擦除remove_if成语 - 删除了什么吗?
- 有没有办法将擦除-删除成语与其他循环条件一起使用
- C4150:删除指向不完整类型和PIMPL成语的指针