std :: remove_if

时间:2016-08-11 05:49:25

标签: c++ asymptotic-complexity remove-if

我正在研究一种数据结构的擦除方法,该数据结构具有硬编码的最大元素数N,它依赖std::array来避免堆内存。虽然std::array只包含N个元素,但是它们中的M是“相关”元素,其中M小于或等于N.例如,如果N是10并且数组看起来像这样:

std::array<int, N> elements = { 0, 1, 2, -1, 4, -1, 6, -1, -1, 9 };

...如果M为7,则只有前7个元素是“相关的”而其他元素被认为是垃圾(结尾{ -1, -1, -9 }是垃圾)。我在这里使用int作为SO示例,但真实程序存储实现operator==的对象。以下是删除所有-1并更新M:

的工作示例
#include <algorithm>
#include <array>
#include <iostream>

constexpr unsigned N = 10;
unsigned           M = 7;
std::array<int, N> elements = { 0, 1, 2, -1, 4, -1, 6, -1, -1, 9 };

int main() {
        for (unsigned i = 0; i < M; ++i)
                std::cout << elements[i] << ' ';
        std::cout << '\n';

        auto newEnd = std::remove_if(
                std::begin(elements), std::begin(elements) + M,
                [](const auto& element) {
                        return -1 == element;
                }
        );

        unsigned numDeleted = M - std::distance(std::begin(elements), newEnd);
        M -= numDeleted;
        std::cout << "Num deleted: " << numDeleted << '\n';

        for (unsigned i = 0; i < M; ++i)
                std::cout << elements[i] << ' ';
        std::cout << '\n';

        return 0;
}

我的问题是std::remove_if的渐近复杂性是什么?我想象在std::remove_ifstd::distance之间它是整体O(2M)或O(M),其中std::remove_if是一个更昂贵的操作。但是我不确定std::remove_if是否为O(N * M),因为每次删除都会移动元素

编辑:为了清楚起见,我理解这应该应用谓词M次,但我想知道每次谓词为真时是否应用了N个移位

2 个答案:

答案 0 :(得分:4)

cppreference

  

复杂性:   谓词的std::distance(first, last)个应用程序。

删除的元素没有移位操作,因为在调用std::remove_if后,它们可能具有未指定的值

答案 1 :(得分:2)

修改

回想起来,这个答案解决了一个比问题更复杂的问题 - 如何在线性时间内实现“推回到结束”功能。关于提出的具体问题 - 与remove_if有关 - @ millenimumbug的答案更好地解决了这个问题。

我明白为什么你会认为复杂性是Θ(mn),因为每个 m 删除的项目可能需要移位 Θ(n)距离。

实际上可以在Θ(n)和其他 O(1)空间(只是几个额外的迭代器)中执行此操作。

考虑下图,显示算法可能实现的迭代。

enter image description here

红色项目是一组连续的已识别项目,此时要删除(此时您只需要两个点来记录)。绿色项目是正在考虑的项目(另一个指针)。

如果要删除绿色项目,红色组只需包含它就会变大。这将在下一个图表中显示,其中红色组展开。在下一次迭代中,绿色项目将是右侧的项目。enter image description here

如果没有,则需要将所有红色组移过它。一些想法可以说服你,这可以在红色组中的线性时间内完成(即使迭代器保证只是前向迭代器)。

为什么复杂性是线性的?因为你可以想象这相当于相对于左组向左移动的绿色元素。理由类似于摊销分析。

下图显示了第二种情况。在下一次迭代中,绿色元素(被考虑)将再次位于红色组的右侧。

enter image description here