在恒定时间内提取子向量

时间:2015-06-25 09:30:13

标签: c++ arrays vector stl time-complexity

我有一个std::vector<int>,我想扔掉x的第一个和最后一个元素。仅复制元素不是一种选择,因为它是O(n)。 是否有类似vector.begin()+=x的东西让向量刚刚开始并在之前结束? 我也试过

items = std::vector<int> (&items[x+1],&items[0]+items.size()-y);

其中的项目是我的向量,但这给了我bad_alloc

3 个答案:

答案 0 :(得分:3)

如果只需要一系列值,则可以将其表示为范围的第一个元素到最后一个元素的一对迭代器。这些可以在固定的时间内获得。

编辑:根据评论中的描述,这似乎是最明智的解决方案。如果你的函数需要一个向量引用,那么你需要重构一下。

其他解决方案:

如果您不需要原始矢量,因此可以修改它,并且元素的顺序不相关,您可以将第一个x元素与n-x-y...n-y元素交换,然后删除最后x+y个元素。这可以在O(x+y)时间内完成。

如果合适,您可以选择使用std::list,如果您有子列表的第一个和最后一个节点的迭代器,那么您可以在恒定时间内完成所要求的内容。这还要求您可以修改原始列表,但元素的顺序不会改变。

如果这些不是选项,那么您需要复制并坚持使用O(n)

答案 1 :(得分:3)

C ++标准算法适用于范围,而不适用于实际容器,因此您无需提取任何内容:您只需调整正在使用的迭代器范围。

void foo(const std::vector<T>& vec, const size_t start, const size_t end)
{
    assert(vec.size() >= end-start);
    auto it1 = vec.begin() + start;
    auto it2 = vec.begin() + end;

    std::whatever(it1, it2);
}

我不明白为什么它需要比这更复杂。

trivial live demo

答案 2 :(得分:2)

其他答案是正确的:通常迭代器都可以。

尽管如此,您还可以编写矢量视图。这是一幅草图:

template<typename T>
struct vector_view
{
    vector_view(std::vector<T> const& v, size_t ind_begin, size_t ind_end)
        : _v(v)
        , _size(/* size of range */)
        , _ind_begin(ind_begin) {}

    auto size() const { return _size; }

    auto const& operator[](size_t i) const
    {
        //possibly check for input outside range
        return _v[ i + _ind_begin ];
    }

    //conversion of view to std::vector
    operator std::vector<T>() const
    {
        std::vector<T> ret(_size);
        //fill it
        return ret;
    }

private:
    std::vector<T> const& _v;
    size_t _size;
    size_t _ind_begin;
}

根据需要公开更多方法(当你想在标准库算法中使用它时,某些迭代器可能是合适的。)

此外,请注意const引用std::vector<T> const& v;的有效性 - 如果这可能是一个问题,那么应该更好地使用共享指针。

在这里也可以考虑更一般的方法,例如,使用步幅或类似的东西。