【问题标题】:Extract subvector in constant time在恒定时间内提取子向量
【发布时间】:2015-06-25 09:30:13
【问题描述】:

我有一个std::vector<int>,我想丢弃第一个和最后一个元素。仅复制元素不是一种选择,因为这是O(n)。 有没有像vector.begin()+=x 这样的东西让向量稍后开始并提前结束? 我也试过了

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

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

【问题讨论】:

  • 也许您应该说明您要解决的高级问题是什么。
  • 你将如何处理提取的向量?可以为begin 和end 迭代器编写一个包装器是一个解决方案吗?这不是真正的vector,不过,它允许您对其进行迭代并访问随机元素。也可以编写push_back 和push_front 方法,它们将替换现有元素,但在这种情况下,您还应该存储原始vector。而且,作为另一种解决方案,您可以看看持久集合的想法。
  • 我正在实施算法来计算装箱问题的下限。在第一步中,我通过在最佳解决方案中丢弃所有单独或成对的物品来减少问题。由于我的向量已排序,因此这些元素是最后一个元素和第一个元素。编辑:我的算法是O(n),我不想把它炸到O(n^2)
  • 为什么你需要“把它炸到O(n^2)”来改变你的迭代范围? o.O
  • 好吧,我把两件事搞混了。它不会损害时间复杂性。

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


【解决方案1】:

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)

【讨论】:

  • 这正是我想要的。但是,尝试您的代码建议,我得到error: it1 doesn't name a type。
  • @Ricardo:仍然停留在 C++03 上?那么你必须写std::vector&lt;T&gt;::const_iterator 而不是auto。 (删除const并酌情设置T)
  • 现在可以了。我还学习了如何启用 C++11。谢谢!
【解决方案2】:

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

编辑:根据 cmets 中的描述,这似乎是最明智的解决方案。如果您的函数需要矢量引用,那么您需要进行一些重构。

其他解决方案:

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

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

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

【讨论】:

    【解决方案3】:

    其他答案是正确的:通常迭代器会这样做。

    不过,您也可以编写矢量视图。这是一个草图:

    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&lt;T&gt; const&amp; v; 的有效性——如果这可能是一个问题,最好使用共享指针。

    这里也可以考虑更通用的方法,例如,使用 strides 或类似的东西。

    【讨论】:

    • @LightnessRacesinOrbit:当然。这就是我写sketch的原因……大致意思是:“我懒得做正确,自己想办法。” ...但是对于明确的建议,我当然会更正它:-)
    猜你喜欢
    • 2021-10-26
    • 2013-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多