Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/134.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在不需要保留顺序时删除擦除习惯用法的改进_C++_Algorithm - Fatal编程技术网

C++ 在不需要保留顺序时删除擦除习惯用法的改进

C++ 在不需要保留顺序时删除擦除习惯用法的改进,c++,algorithm,C++,Algorithm,流行的remove\u if-erase习惯用法保留了保存在容器中的元素的顺序。我有一个例子,我想删除一些元素,但我不关心其余元素的顺序,因为它们稍后将被移动。因此,我认为,我可以扫描向量,而不是使用remove_if-erase,当找到要删除的元素时,我可以将其与向量的最后一个有效元素交换。我将此习语称为swap-erase,它可以很容易地实现如下: template<typename Object, typename Condition> void swap_erase(std:

流行的remove\u if-erase习惯用法保留了保存在容器中的元素的顺序。我有一个例子,我想删除一些元素,但我不关心其余元素的顺序,因为它们稍后将被移动。因此,我认为,我可以扫描向量,而不是使用remove_if-erase,当找到要删除的元素时,我可以将其与向量的最后一个有效元素交换。我将此习语称为swap-erase,它可以很容易地实现如下:

template<typename Object, typename Condition>
void swap_erase(std::vector<Object>& v, const Condition& condition) {
    // Keeps track to one past the last element we want to keep.
    auto iter_to_last = v.end();

    for(auto it = v.begin(); it < iter_to_last; ++it) {
        // If the erasure condition is fulfilled...
        if(condition(*it)) {
            // Increase by one to the left the "tail" of the
            // vector, made by elements we want to get rid of;
            // Swap the two elements.
            // Rewind the current iterator by 1, so at the
            // next iteration we test the element we just swapped.
            std::iter_swap(it--, --iter_to_last);
        }
    }

    // Erase the elements we pushed at the end of the queue.
    v.erase(iter_to_last, v.end());
}
你关于移除_if如何工作的假设可能是错误的。也许你应该明确地说出来

如果最多只移动一次每个未删除的元素,则基本上移除_,因此如果删除了大多数元素,则速度尤其快。它可以通过首先扫描未被删除的阵列的初始部分进行优化,在这种情况下,如果删除的元素很少,并且第一个删除的元素接近尾端,那么它也会很快


交换算法对删除的每个元素进行一次交换,因此,如果删除的元素很少,则交换速度最快。但互换是不必要的,而且在某些情况下速度不必要地慢,因为它需要三步走。您只需将最后一个元素移到要删除的元素上方,可能会保存两个数据副本。

几年前我做了同样的事情,最终得到了相同的结果。我想这是因为cpu缓存。我相信这是因为没有办法告诉v.橡皮擦最后,v.end;您正试图从向量末尾删除的。因此,它将其视为任何其他调用,即vec.erasebegin_itr,end_itr,这需要时间。奇怪的是,我在几年前也这样做了,并发现它的速度要快得多,在某些情况下是几个数量级。除了在某些情况下执行相同的操作外。@ViktorSehr缓存位置对于这两种方法应该是相同的,我认为?@VikashKesarwani但瓶颈应该是每次删除\u(如果命中)时进行的所有移动,而不是擦除。但是,我同意,有一个O1尾部擦除会很好。你是对的,我的假设是错误的,即remove_if的复杂性应该比它实际的复杂,我将更新这个问题,编写remove_if的可能实现,它概述了这一点。
template<typename ForwardIterator, typename Predicate>
ForwardIterator remove_if(ForwardIterator first, ForwardIterator last, Predicate pred) {
    first = std::find_if(first, last, pred);

    if(first == last) {
        return first;
    }

    ForwardIterator result = first;
    ++first;

    for(; first != last; ++first) {
        if(!pred(first)) {
            *result = std::move(*first);
            ++result;
        }
    }

    return result;
}