我需要从符合某个标准的向量中删除所有元素。
我的第一种方法是遍历向量并在符合条件的所有元素上调用vector :: erase。
据我所知,vector::erase
对于这个用例有一个糟糕的表现,因为它从底层数组中删除了项目,并将向量的其余部分向前移动了一个元素(如果擦除则更多)一系列元素)。
当您移除多个元素时,后移元素将在每次移除时移动。
remove
算法将所有元素移除,并将它们移动到向量的末尾,因此您只需要移除向量的后部,这不会移位。
但为什么这比擦除更快?(它更快吗?)
不将元素移动到最后意味着像vector::erase
一样向前移动所有后续元素?
为什么删除只有复杂的O(n)?
答案 0 :(得分:7)
这里的性能问题不是要删除要删除的元素,或者将它们移动到最后(实际上不会发生),而是关于移动要保留的元素
如果您对要移除的每个元素使用erase
,则需要在每个元素之后移动所有元素...每次调用erase
。通常情况下,如果要删除k
元素,则会将元素移动到最新元素之后(在向量中)k
次,而不是仅移动一个元素。
但是如果你致电remove
,你只会移动一次(见下面的例子)。
一个小例子,可以更好地理解这两种方法的工作原理:
假设你有一个大小为1000的向量,你要删除的元素位于第17和37位。
erase
对要移除的两个元素起作用:
erase()
时,您需要将元素18移动到999,982个元素。erase()
时,您需要将元素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上的possible implementation,以便更好地了解std::remove
的工作原理。
答案 1 :(得分:4)
优势在于std::remove
不是一次只删除一个元素。例如,如果调用SELECT P, G, T FROM C_I l1 , C_II l2
WHERE
ABS(l1.P-l2.P) < 0.005
AND
ABS(l1.T-l2.T) < 20.0
AND
ABS(l1.G-l2.G) < 0.005;
导致移除矢量的前10个元素,它会将第11个元素直接移动到第1个位置,第12个元素直接移动到第2个位置等等......然而,如果你一次擦除前10个元素,它会将你擦除的每个元素移回1.然后你将擦除下一个元素,每个元素都必须再次移动。对于每个被删除的元素,这都会重复。
此外,为了实现这一优势,删除的元素不必是顺序的。例如,如果要删除的调用会导致每个其他元素,从第一个开始,将被删除。首先,第二个元素将移动到第一个位置,这将留下两个元素的间隙,直到下一个可保持元素。然后第4个元素将直接移动到第2个位置,留下3个元素的间隙,依此类推。
另外,稍作修正:
remove算法将删除所有元素,并将它们移动到向量的末尾
删除算法不会这样做。它并不关心要删除的元素会发生什么。它们只是被要保留的元素所取代。未指定调用remove之后的结尾元素的值。您描述的算法是分区(具有反向比较功能)。